如何在命令行上预先构造awk语句传递给awk?

时间:2010-07-02 15:01:25

标签: shell cygwin awk

我有一个shell脚本,它将一个awk程序构造为一个字符串,然后将该字符串传递给awk。这是因为我想在awk程序中使用shell变量的值。

我的代码如下所示:

awk_prog="'{if (\$4~/$shell_var/) print \$1,\$2}'"
echo $awk_prog
awk $awk_prog $FILENAME

但是,当我将字符串传递给awk时,我总是收到错误:

'{if ($4~/regex/) print $1,$2}'
awk: '{if
awk: ^ invalid char ''' in expression

该错误消息是什么意思?我尝试了-F:开关,但没有帮助。我该如何解决这个问题?

谢谢。

3 个答案:

答案 0 :(得分:5)

这是由shell引用引起的。以下内容适用:

awk_prog="{ if (\$4 ~ /$shell_var/) print \$1, \$2 }"
echo "$awk_prog"
awk "$awk_prog" $FILENAME

当您从命令行运行awk '{ print }' foo时,shell解释并删除程序周围的引号,以便awk接收两个参数 - 第一个是程序文本,第二个是文件名foo。您的示例是向awk发送程序文本'{if ...}',就awk而言,这是无效的语法。外部引号不应出现。

在上面给出的代码段中,shell使用awk_prog=行中的引号将字符串的内容分组为单个值,然后将其分配给变量awk_prog。当它执行awk "$awk_prog"...行时,你必须引用$awk_prog的扩展,以便awk接收程序文本作为单个参数。

答案 1 :(得分:4)

还有另一种方法可以将你的shell变量变成awk - 使用awk的-v选项:

awk -v pattern="$shell_var" '$4 ~ pattern {print $1, $2}' "$FILENAME"

如果要将多个变量传递给awk,请多次使用-v。

如果您真的想要将awk程序保存在shell变量中,请使用printf进行构建:

awk_script="$( printf '$4 ~ /%s/ {print $1, $2}' "$shell_var" )"
awk "$awk_script" "$FILENAME"

注意printf命令中引号的使用:模板周围的单引号保护你想要awk解释的美元符号,shell变量的双引号。

答案 2 :(得分:1)

另一个(IMO更简单)解决方案(我认为)解决了你直觉上想要做的只是使用eval。您希望shell的行为就像您按字面输入一样:

awk '{if ($4~/foo/) print $1,$2}' path

(其中foo和path是$ shell_var和$ FILENAME的文字内容)。为了实现这一点,只需在最后一行的前面拍一个eval(也许是好的衡量标准,但在这种情况下它们不是必需的),这样你的最后一行就是:

eval "awk $awk_prog $FILENAME"