awkスクリプトにパラメータを渡す

awkスクリプトにパラメータを渡す

N引数をstdinに渡し、stdinから読み取ることができるようにしたいawkスクリプトがあります。私は次のことができるようにしたいと思います。

tail -f logfile | my_cool_awk_scipt var1 var2 var3 ... varN

次に、スクリプトでこれらの変数を使用します。

#!/bin/awk -f

BEGIN { 
print "AWK Script Starting" 
print ARGV[1]
}                                                                              
{
    if ($0 < ARGV[1])
        print $0
    else if ($0 < ARGV[2])
        print $0 + ARGV[2]             
}
  

変数を渡そうとすると、印刷された次のARGV[1]エラーが発生します。

awk: ./my_cool_awk_script:4: fatal: cannot open file `var1' for reading (No such file or directory)

私はできます、

tail -f logfile | my_cool_awk_scipt -v var1=var1 -v var2=var2 -v var3=var3 ... varN=varN

しかし、これは少し制限的で長いです。私はこれをシェルスクリプトでラップすることができることを知っていますが、私が持っているものを似たようなものに含めるためのきちんとした方法があるかどうかはわかりません。

答え1

awkがスクリプト本体に到達した瞬間、BEGINARGV [x]で指定されたファイル名を読み取ろうとします。だからちょうど核を撃つ。

$ cat a.awk
#!/bin/awk -f
BEGIN {
print "AWK Script Starting"
ZARGV[1]=ARGV[1]
ZARGV[2]=ARGV[2]
ARGV[1]=""
ARGV[2]=""
}
{
    if ($0 < ZARGV[1])
        print $0
    else if ($0 < ZARGV[2])
        print $0 + ZARGV[2]
}
$

例:

$ cat logfile
1
2
3
4
5
$ ./a.awk 3 4 <logfile
AWK Script Starting
1
2
7
$

答え2

ただの楽しみで(これは確かに推奨されるアプローチではありません):awk「位置パラメータ」(PP)は知らず、変数の割り当てと入力ファイル名だけがわからないため、PPを分析して他の2つと区別する必要があります。これは、PPを固定トークンに分割するか--(他の状況でも使用されます)、PPの数(固定またはARGV [1]で送信)を特定することによって実行できます。努力する

    awk '
    BEGIN   {while (ARGV[++MXPP] != "--")   PP[MXPP]     = ARGV[MXPP]
             for (j=MXPP+1; j<ARGC; j++)    ARGV[j-MXPP] = ARGV[j]
             ARGC -= --MXPP
            }

            {if ($0 < ARGV[1])
             print $0
             else if ($0 < ARGV[2])
             print $0 + ARGV[2]             
            }
    ' VAR1 VAR2 -- file[12]

入力ファイルの代わりにstdinに入力をパイプする場合は、トークンを省略してリストの最後までPPを取得できます(つまり、トークンを ""に設定)。

答え3

あなたはすでにこれを知っています-v variable=value。別の方法は、環境を介して変数を渡して配列から読み取ることですENVIRON

$ var1=hello var2=world awk 'BEGIN { print ENVIRON["var1"], ENVIRON["var2"] }'
hello world

var1これは環境でのみvar2環境変数を設定します。awk

または、

$ export var1=hello var2=world
$ awk 'BEGIN { print ENVIRON["var1"], ENVIRON["var2"] }'
hello world

これは、呼び出し前に呼び出し環境の変数を設定しますawk

配列には、プログラムが順次読み取るファイル名のみが含まれますが、ARGV次のようにコマンドラインで設定された変数名も含めることができます。awk

awk '...' var1=value1 var2=value2 filename

これは一般的にいいえ変数を渡すための推奨方法(たとえば、awkこれらの変数はブロックでは使用できません)BEGIN

答え4

次のスクリプトを作成できます。

#!/bin/bash   
vars=()
i=1
for arg in "$@"; do
    vars+=(-v "var$i=$arg")
    i=$((i+1))
done

awk "${vars[@]}" -f/dev/fd/3 3<< EOF
BEGIN {
    printf "awk var1: %s\n", var1;
    printf "awk var2: %s\n", var2;
}
1
EOF

次に実行します。

$ echo some input | ./awk.sh foo bar doo
awk var1: foo
awk var2: bar
some input

シェルスクリプトはこれらの引数のコマンドラインを作成し、-v var1=...here-docを介して実際のawkプログラムに渡しますawk(もちろん、awkスクリプトを別のファイルに入れることができます)。ただし、この方法では入力ファイルの名前を渡すことはできず、stdinからawkスクリプトを読む必要があります。

少なくともGNU awkは、ARGV[n]入力ファイルとして使用される内容を明確に文書化します(https://www.gnu.org/software/gawk/manual/html_node/ARGC-and-ARGV.html)、これが「ファイルが見つかりません」エラーが発生する理由です。

関連情報