AWK を使用して検索と置換を行うときに引用符を表示するにはどうすればよいでしょうか?

AWK を使用して検索と置換を行うときに引用符を表示するにはどうすればよいでしょうか?

現在、私は AWK を使用して、文字列の最初の 3 つの出現部分を検索して置換しています。文字列は次のようにフォーマットされており、ファイルには次のような文字列が多数あります。

func(tempID="39849235",count='12');

使用このリンクAWK を使用して文字列の最初の 3 つのインスタンスを検索して置換する方法を見つけることができました。必要な操作に合わせて変更しました。スクリプトの一部を以下に示します。

id=12349876
awk 'BEGIN {matches=0}
     matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID='"$id"'"); matches++ }
     { print $0 }' filName.py >filName.py.changed

上記のコードの目的は、tempID を含む任意の行に一致し、tempID に割り当てられた番号を という変数に保持されている値に置き換えることです$id。検索と置換はうまく機能しますが、1 つの問題は、どのように構造化しても、出力に引用符なしで $id が印刷されることです。引用符をエスケープして単一のティックを挿入してみましたが、いずれにしても行は次のように変更されます。

func(tempID=39849235,count='12');

置換部分を囲む二重引用符を削除して として構造化してみましたtempID="$id"が、残念ながら ID 番号が文字列 に置き換えられるだけです$id

tempID 値を検索して置換し、その値を引用符で囲む方法があるかどうか教えてください。私は AWK にこだわっているわけではないので、sed などの他のユーティリティを使用した他の方法でも問題なく動作します。

答え1

コマンドには、シェルによって解釈され削除される引用符と、によって解釈され削除される引用符がありますawk。そのため、存続する引用符が必要です。それらをエスケープする必要があります。

id=12349876
awk 'BEGIN {matches=0}
 matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID=\"'"$id"'\""); matches++ }
 { print $0 }' filName.py >filName.py.changed              # ^^  here ^^

説明。元のコマンドは次のようになります

awk 'BEGIN {matches=0} matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID='"$id"'"); matches++ } { print $0 }'
#   ^ these quotes are seen by the shell and don't get to awk                      ^^   ^^                            ^
#     these quotes get to awk and serve their purpose there      ^      ^  ^              ^
#     this variable is expanded by the shell and gets to awk as its value            ^^^

改善されたコマンドは次のようになります。

awk 'BEGIN {matches=0} matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID=\"'"$id"'\""); matches++ } { print $0 }'
#   ^ these quotes are seen by the shell and don't get to awk                        ^^   ^^                              ^
#     these quotes get to awk and serve their purpose there      ^      ^  ^                  ^
#     these quotes will appear in the output thanks to being escaped                ^        ^
#     this variable is expanded by the shell and gets to awk as its value              ^^^

引用符の乱用を減らすには、-vオプションを使用して変数を に渡しますawk。そうすれば、シェルが を展開できるようにするために、シーケンスの途中で一重引用符を閉じて再度開く必要がなくなります$id。代わりに、引用符なし (としてawk認識)は独自idに によって展開されますawk。追加する必要がある二重引用符は、以前と同様にエスケープする必要があります。

id=12349876
awk -v id="$id" 'BEGIN {matches=0}
 matches < 3 && /.*tempID.*/ { sub(/tempID="[0-9]+"/,"tempID=\""id"\""); matches++ }
 { print $0 }' filName.py >filName.py.changed

答え2

やりたいことを達成するには、次のことが必要です。

二重引用符の場合:

  • AWK: 二"重引用符内の二重引用符をエスケープします。
    $1 $2=> foobar
    $1" __"$2"__"=> foo __bar__
    $1" \""$2"\""=>foo "bar"

一重引用符の場合:

  • シェル:内部の'…'別のセットを使用して、awk スクリプト全体を終了します。 =>'…'
    'escaped 'unescaped' escaped'
    '$LINUX '$OSTYPE' $CPUTYPE'$LINUX linux-gnu $CPUTYPE

  • Shell:'文字通りに印刷したいエスケープ。
    'apostrophe that'\''s literal'=>apostrophe that's literal

例えば

echo foo bar | awk '{print "\""$1"\" '\''"$2"'\''"}'
"foo" 'bar'

関連情報