awkでシェル変数を使用する

awkでシェル変数を使用する

これは私のスクリプトです(指定されたパターンを含むファイルを見つけるため)。

find . -type f \
    -exec awk -v vawk="$1" '/'"$vawk"'/ {c++} c>0 { print ARGV[1]; exit 0 } END { if (! c) {exit 1}}' \{\} \;

パラメータ付きのスクリプトを使用したいです§:

MyScript.sh pattern

私の問題は$1変数をawk

私のスクリプトをデバッグしようとしたとき

bash -x MyScript.sh pattern

出力は次のとおりです。

+ find . -type f -exec awk -v vawk=pattern '// {c++} c>0 {print ARGV[1] ; exit 0 } END { if (! c) {exit 1}}' '{}' ';'

変数$vawkが空のようです。

どんなアイデアがありますか?

答え1

awk変数とシェル変数を混同しているようです。 awk -v vawk="$1"作るアッ変数名が指定されましたが、vawk使用しようとしています。シェル構文($vawk)。シェルにという変数がないため、機能しませんvawk。私の考えでは、あなたが望むもの

awk -v vawk="$1" '$0 ~ vawk { c++ } # ...'
#                      ^ awk variable syntax

答え2

今後今は次のように閉鎖されています。コピー質問これには、awkの変数転送制限に関する警告が含まれているため、便利です。

シェル変数は次のとおりです。シェル変える。それをアッ変数には次の構文が必要です。

awk -v x="$x" '$2 == x {print $1}' infile

または

awk '$2 == x {print $1}' x="$x" infile

しかし、問題が発生します。エスケープシーケンスが拡張されます。

また、GNU awk4.2以上の場合、$xで始まり@/終わる場合は、/正規表現型の変数として扱われます。)。

たとえば、シェル変数に2つの文字が含まれている場合バックスラッシュそしてN、awk変数には最終的に次のものが含まれます。新しいチーム文字とgawk 4.2+の場合が含まれている場合、@/foo/awk変数にはが含まれてfoo型になりますregexp。さらに悪いことに、@/(xxxxx){1,20000}/gawkが数時間またはメモリが不足するまでCPUを占有して正規表現をコンパイルしようとすると、DoSの脆弱性の一種になることがあります。

別の方法(しかし-vPOSIX awkまたはnawkが必要です(Solarisでまだ使用されている1970年代awkとは反対/bin/awk))は、環境変数を使用することです。

x="$x" awk '$2 == ENVIRON["x"] {print $1}' infile

別の方法(まだ最新のawkを使用)は、awkでARGV配列を使用することです。

awk -- 'BEGIN {x = ARGV[1]; delete ARGV[1]}
  $2 == x {print $1}' "$x" infile

また、 //ARGVまたは引数を使用しても、対応する文字列は次のように処理されます。ENVIRON-vvar=value数値文字列数値型の場合(認識される数値形式の範囲は実装によって異なります)。

上記の例では、orであれば$2 == ENVIRON["VAR"]文字列比較になりますが、or(または実装とバージョンによって)であれば数値比較になるので重要です。数字です。したがって、とは同じと見なされます。$VARfoo1f21e21.1inf0xffawk$210.0e11001e2

行為:

awk 'BEGIN {var = "" ENVIRON["VAR"]}'

シェル変数が数値のように見えても、var awk変数は常に文字列として扱われていることを確認してください。$VAR

awk 'BEGIN {var = 0 + ENVIRON["VAR"]}'

これを数値に変換します(少なくとも前の部分は数値として解釈できます)。


あるいは、strcoll()いくつかの実装(POSIXで要求されているように)と比較した場合、つまり、どちらか一方または両方が同じソート順を持つ場合、1つa == bまたはa両方が文字列の場合はbtrueを返します。ab

関連情報