为什么将这个awk命令与eval嵌套会产生与运行它不同的结果?

时间:2019-01-22 18:20:58

标签: bash awk

我有这个脚本,旨在将变量分配给命令,这些命令收集有关系统的信息,然后将其回显。这对于前几个命令非常有效,但是最后一个命令继续返回值,而不会从输出中删除“ PRETTY_NAME =“。

我没有看到这个问题吗?

我尝试使用grep分隔awk:

grep PRETTY_NAME /etc/*-release | awk -F '=' '{print $2}'

使用转义引号:

awk -F \"=\" '/PRETTY_NAME/ {print $2}' /etc/*-release

整块(相关性进行了一些编辑)

declare -A CMDS=(
   [primaryMacAddress]="cat /sys/class/net/$(ip route show default | awk '/default/ {print $5}')/address" 
   [primaryIpAddress]="hostname --ip-address"
   [hostname]="hostname"
   [osType]="awk -F '=' '/PRETTY_NAME/ {print $2}' /etc/*-release"
   )

#This bit is actually nested in another function
for kpair in "${!CMDS[@]}" do
   echo "$kpair=\"$( eval ${CMDS[$kpair]} )\""
done 

从.sh文件运行时的结果:

  

osType =“ PRETTY_NAME =” Red Hat Enterprise Linux Server 7.4(Maipo)“”

预期:

  

osType =“”红帽企业版Linux服务器7.4(Maipo)“”

单独运行此命令时,它似乎可以正常运行:

  

$ awk -F'=''/ PRETTY_NAME / {print $ 2}'/ etc / *-release

     
    

“ Red Hat Enterprise Linux Server 7.4(Maipo)”

  

1 个答案:

答案 0 :(得分:1)

由于您的Awk命令用双引号指定,因此内部美元符号会受到特殊处理:$2被shell视为参数替换,因此array元素不存储文本{ {1}},而是它的扩展。 Awk解释器永远不会看到$2语法。

但是,命令调度程序中还有第二个问题。您的$2命令不会阻止单词拆分:

eval

您想要这个:

eval ${CMDS[$kpair]}

不带引号,您的命令被任意切成空白。然后eval "${CMDS[$kpair]}" 将片段连接在一起,并在它们之间使用一个空格,并评估结果语法。可以通过以下示例来证明差异:

eval

我们可以使用$ cmd="awk '/foo/ { print \$1\" \"\$2 }'" $ echo 'foo a' | eval $cmd foo a $ echo 'foo a' | eval "$cmd" foo a 来了解问题:

echo

$ echo $cmd awk '/foo/ { print $1" "$2 }' $ echo "$cmd" awk '/foo/ { print $1" "$2 }' 的替换和随后的单词拆分均与cmd包含的任何shell语法无关。我们可以看到这样的片段:

$cmd

当我们执行$ for x in $cmd ; do echo "<$x>" ; done <awk> <'/foo/> <{> <print> <$1"> <"$2> <}'> 时,上面的片段将由eval $cmd生成并重新组合并进行评估。不用说,您不希望这样分割命令语法并将其重新组合;谁知道会出现什么样的隐藏错误。您现在拥有的命令可能还可以,但是作为一种通用的命令分配机制,它存在缺陷。