我有一个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:开关,但没有帮助。我该如何解决这个问题?
谢谢。
答案 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"