web-dev-qa-db-ja.com

Awkスクリプトでシェル変数を使用する方法

外部のシェル変数をawkスクリプトに渡す方法をいくつか見つけましたが、'"について混乱しています。

まず、私はシェルスクリプトを試してみました:

$ v=123test
$ echo $v
123test
$ echo "$v"
123test

その後awkを試してみました:

$ awk 'BEGIN{print "'$v'"}'
$ 123test
$ awk 'BEGIN{print '"$v"'}'
$ 123

違いは何ですか?

最後にこれを試しました:

$ awk 'BEGIN{print " '$v' "}'
$  123test
$ awk 'BEGIN{print ' "$v" '}'
awk: cmd. line:1: BEGIN{print
awk: cmd. line:1:             ^ unexpected newline or end of string 

私はこれについて混乱しています。

223
hqjma

シェル変数をawkにする

いくつかの方法で行うことができます。他のものより優れているものもあります。これはそれらのほとんどをカバーするはずです。コメントがある場合は、下に残してください。


-vを使う(最善の方法、最も移植性が高い)

-vオプションを使用します。(P. S. -vの後にスペースを使用すると、移植性が低下します。たとえば、awk -v var=awk -vvar=ではなく)

variable="line one\nline two"
awk -v var="$variable" 'BEGIN {print var}'
line one
line two

これはほとんどのawkと互換性があるはずで、変数はBEGINブロックでも利用可能です。

複数の変数がある場合

awk -v a="$var1" -v b="$var2" 'BEGIN {print a,b}'

警告 。 Ed Mortonが書いているように、エスケープシーケンスは解釈されるので\tは本当のtabとなり、それがあなたが探しているものであれば\tとはなりません。 ENVIRON[]を使用するかARGV[]経由でアクセスすることで解決できます


コードブロック後の変数

ここでawkコードの後に​​変数を取得します。 BEGINブロックに変数が必要ない限り、これはうまくいきます。

variable="line one\nline two"
echo "input data" | awk '{print var}' var="${variable}"
or
awk '{print var}' var="${variable}" file

これは複数の変数awk '{print a,b,$0}' a="$var1" b="$var2" fileでも動作します

このように変数を使用しても、BEGINブロックでは機能しません。

echo "input data" | awk 'BEGIN {print var}' var="${variable}"

ヒアストリング

それらをサポートするシェル(/ bashを含む)から here-string を使用して、変数をawkに追加することもできます。

awk '{print $0}' <<< "$variable"
test

これは以下と同じです。

printf '%s' "$variable" | awk '{print $0}'

P.Sこれは変数をファイル入力として扱います。


ENVIRON入力

TrueYが書いているように、ENVIRONを使って 環境変数 を表示することができます。 AWKを実行する前に変数を設定すると、次のように出力できます。

X=MyVar awk 'BEGIN{print ENVIRON["X"],ENVIRON["Shell"]}'
MyVar /bin/bash

ARGV入力

Steven Pennyが書いているように、データをawkに入れるためにARGVを使うことができます。

v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data

BEGINだけでなく、データをコード自体に取り込むには、次のようにします。

v="my data"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"
my data test

コード内の変数:USE WITH CAUTION

awkコード内で変数を使用できますが、厄介で読みにくく、Charles Duffyが指摘するように、このバージョンもコードインジェクションの犠牲になる可能性があります。誰かが変数に悪いものを追加した場合、それはawkコードの一部として実行されます。

これはコード内の変数を抽出することで機能するので、その一部になります。

変数を使用して動的に変化するawkを作成したい場合は、この方法で実行できますが、通常の変数には使用しないでください。

variable="line one\nline two"
awk 'BEGIN {print "'"$variable"'"}'
line one
line two

これがコードインジェクションの例です。

variable='line one\nline two" ; for (i=1;i<=1000;++i) print i"'
awk 'BEGIN {print "'"$variable"'"}'
line one
line two
1
2
3
.
.
1000

このようにしてawkにたくさんのコマンドを追加することができます。無効なコマンドでもクラッシュさせます。


追加情報:

二重引用符の使用

変数"$variable"を二重引用符で囲むのは常に良いことです。
そうでなければ、複数の行が長い単一行として追加されます。

例:

var="Line one
This is line two"

echo $var
Line one This is line two

echo "$var"
Line one
This is line two

あなたが二重引用符なしで得ることができる他のエラー:

variable="line one\nline two"
awk -v var=$variable 'BEGIN {print var}'
awk: cmd. line:1: one\nline
awk: cmd. line:1:    ^ backslash not last character on line
awk: cmd. line:1: one\nline
awk: cmd. line:1:    ^ syntax error

そして一重引用符では、変数の値を拡張しません。

awk -v var='$variable' 'BEGIN {print var}'
$variable

AWKと変数に関する詳細

このよくある質問を読んでください

390
Jotne

古き良きENVIRONawk 組み込みハッシュはまったく言及されていないようです。その使用例

$ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}'
Solaris rxvt
24
TrueY

シェル変数のバックスラッシュの扱い方に応じて、これらのいずれかを使用します(avarはawk変数、svarはシェル変数です)。

awk -v avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file

詳細と他のオプションについては http://cfajohnson.com/Shell/cus-faq-2.html#Q24 を参照してください。上記の最初の方法はほとんど常にあなたの最良の選択肢であり、最も明白な意味論を持っています。

8
Ed Morton

コマンドラインオプション-vに、変数名(v)と環境変数(=)の値("${v}")を指定して渡すことができます。

% awk -vv="${v}" 'BEGIN { print v }'
123test

もっと明確にするには(はるかに少ないvsで):

% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test
5
Johnsyweb

あなたはARGVを利用することができます:

v=123test
awk 'BEGIN {print ARGV[1]}' "$v"

あなたが身体の中に続けようとしているならば、あなたはARGCを調整する必要があるでしょう:

awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"
3
Steven Penny

ログファイルの行の先頭に日付を挿入する必要があり、それは以下のように行われます。

DATE=$(date +"%Y-%m-%d")
awk '{ print "'"$DATE"'", $0; }' /path_to_log_file/log_file.log

保存するために別のファイルにリダイレクトすることができます

1
Sina
for i in chr{1..22} chrX chrY
do
awk -v chr="$i" '$1==chr' ../snp150.hg19.txt >> $chr.vcf.bed
echo $i
done
0
Shicheng Guo

@ Jotneの答えを「for loop」に変更しただけです。

for i in `seq 11 20`; do Host myserver-$i | awk -v i="$i" '{print "myserver-"i" " $4}'; done
0
edib