web-dev-qa-db-ja.com

awkスクリプトに引数を渡す

N個の引数を渡して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

しかし、これは少し制限的で冗長です。私はこれをシェルスクリプトでラップすることもできますが、私が持っているものをそのようなものに埋め込むクリーンな方法がわかりません。

よろしくお願いします。

3
AdamR

Awkがスクリプトの本体に到達した瞬間、BEGINの後に、ARGV [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
steve

それを楽しむためだけに(そしてこれは確かには推奨される方法ではありません):awkは「位置パラメータ」(PP)を認識せず、変数の割り当てのみを認識しますファイル名を入力し、PP outを分析して他の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を使用してsthをパイプする場合、トークンを省略して、リストの最後までPPをフェッチすることができます(つまり、トークンを ""に設定します)。

2
RudiC

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

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

これにより、awkの環境でのみ環境変数var1およびvar2が設定されます。

または、

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

これにより、awkを呼び出す前に、呼び出し環境で変数が設定されます。

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

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

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

0
Kusalananda

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

#!/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=...引数、およびそれらをawkに、実際のawkプログラムとともにhere-docを介して渡します(もちろん、代わりにawkスクリプトを別のファイルに含めることもできます)。この方法で入力ファイルの名前を渡すことはできませんが、awdスクリプトをstdinから読み込ませる必要があります。

少なくともGNU awkはARGV[n]も入力ファイルとして使用されます( https://www.gnu.org/software/gawk/manual/html_node/ARGC-and-ARGV.html )。これが、 「ファイルが見つかりません」エラー。

0
ilkkachu