環境変数がコマンドライン引数内で展開されていません

環境変数がコマンドライン引数内で展開されていません

「usernumber」と「process id」の 2 つの列を持つファイルがありますuser-pid.out2。usernumber に基づいて、対応するプロセス ID を見つけたいです。以下の最初の 2 行では出力が正しく表示されませんが、3 行目と 4 行目でユーザーを 62 としてハードコードすると、ユーザー 62 に対応するプロセス ID が表示されます。どなたか助けていただけませんか。

USR=62
usrpid=`awk '$1 == "$USR" {print $2}' /home/hu/batchhu/dbscripts_tst2/user-pid.out2`
echo "first:" $USR $usrpid
# This shows 62 and blank for process id

usrpid=`awk '$1 == "62" {print $2}' /home/hu/batchhu/dbscripts_tst2/user-pid.out2`
echo  "second:" $USR $usrpid
# This shows 62 and process id corresponding to this user in the file user-pid.out2

答え1

@artm は、awk スクリプトを二重引用符で囲み、さまざまな文字をエスケープするテクニックを示しました。他の 3 つのテクニックを以下に示します。

シェルが変数を展開できるように、一重引用符を外す

usrpid=$(awk '$1 == "'"$USR"'" {print $2}' file)

シェル変数をawk変数に渡す

usrpid=$(awk -v usr="$USR" '$1 == usr {print $2}' file)

変数がエクスポートされている場合は、awkのENVIRON配列を使用します。

usrpid=$(awk '$1 == ENVIRON["USR"] {print $2}' file)

後者のほうが好ましいでしょう。

@artmのような最初のアプローチでは、シェル変数の内容がawkコード内に埋め込まれているため、コマンドインジェクション脆弱性変数の内容が厳密に制御されていない場合(たとえば、 の場合USR='blah" || system("reboot") || "'、 が呼び出されますreboot)。

2 番目はコマンド インジェクションの脆弱性を導入しませんが、$USRバックスラッシュ文字が含まれている場合、 C のようなバックスラッシュ エスケープ シーケンスが展開されるため、変数にはシェル変数usr awkと同じものが含まれません。$USRawk

を使用すると、ENVIRONこれらの問題は発生しません。

答え2

最初の例の"$USR"は、一重引用符で囲まれた文字列 の中にあるため展開されません'$1 == "$USR" { print $2 }'。そのため、このコードは、最初の列が 62 ではなく "$USR" である行を検索します。

次のようにすれば動作するはずです:

usrpid=$(awk "\$1 == \"$USR\" {print \$2}" /home/hu/batchhu/dbscripts_tst2/user-pid.out2)

変更点:

  1. awkのコマンドラインでは二重引用符が使用されるため、$USRが展開されます。
  2. awkプログラム内のドル記号と引用符はエスケープされます
  3. $()バッククォートの代わりに使用されるのでバックスラッシュは正しく処理されます

の値はUSRawk スクリプトに直接挿入されるため、その値に awk が文字どおりに解釈する文字のみが含まれている場合にのみ機能することに注意してください。 または が含ま$USRれている場合、大変なことになります。 — は awk 文字列リテラルの終わりとなり、次の文字が引用符で囲まれます。\""\

関連情報