将参数传递给 awk 脚本

将参数传递给 awk 脚本

我有一个 awk 脚本,我希望能够将 N 个参数传递给它并从 stdin 读取。我希望能够做类似的事情

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

但这有点限制和冗长。我知道我也可以将其包装在 shell 脚本中,但我不确定是否有一种干净的方法将我所拥有的内容嵌入到类似的东西中。

答案1

当 awk 到达脚本主体的那一刻, after 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

只是为了好玩(这是当然不是推荐的方法):由于awk不知道“位置参数”(PP),而只知道变量分配和输入文件名,因此我们需要剖析 PP 并将它们与其他两个区分开来。这可以通过用固定令牌分隔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

shell 脚本将构建这些参数的命令行-v var1=...,并通过here-doc 将它们传递awk给实际的 awk 程序(当然,您可以将 awk 脚本放在单独的文件中)。但是,您不能以这种方式传递输入文件的任何名称,您必须从 stdin 读取 awk 脚本。

至少 GNU awkARGV[n]也明确记录了用作输入文件的内容(https://www.gnu.org/software/gawk/manual/html_node/ARGC-and-ARGV.html),这就是您收到“文件未找到”错误的原因。

相关内容