【问题标题】:Why does nesting this awk command with eval produce a different result than running it?为什么用 eval 嵌套这个 awk 命令会产生与运行它不同的结果?
【发布时间】:2019-06-16 06:43:24
【问题描述】:

我有这个脚本,旨在将变量分配给收集有关系统信息的命令,然后将它们回显。这对于前几个命令非常有效,但最后一个命令会继续返回值,而不会从输出中删除“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=""Red Hat Enterprise Linux Server 7.4 (Maipo)""

当此命令自行运行时,它似乎按预期工作:

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

“红帽企业 Linux 服务器 7.4(迈坡)”

【问题讨论】:

  • $2 在双引号内展开。请改用\$2。或者只是......使用函数,这太糟糕了:)
  • @PesaThe 不幸的是,由于脚本其余部分的结构,这是我可以管理此部分的最佳方式,但这确实解决了我的问题。谢谢。
  • 第一个条目应该有同样的问题,$(ip route...) 过早扩展。如果这确实是个问题。
  • @ncfx1099 在 shell 中,使用 eval 几乎总是一个糟糕的选择。您可能想问另一个问题,在哪里解释“脚本其余部分的结构”以及为什么会导致您使用此代码。我希望人们能够为您提供更好的方法。

标签: bash awk


【解决方案1】:

因为您的 awk 命令是用双引号指定的,所以内部美元符号受到特殊处理:$2 被您的 shell 视为参数替换,因此数组元素不存储文本 $2而是它的扩展。 awk 解释器永远不会看到$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 的替换和随后的分词操作与 `cmd 包含的任何 shell 语法无关。我们可以看到这样的片段:

$ for x in $cmd ; do echo "<$x>" ; done
<awk>
<'/foo/>
<{>
<print>
<$1">
<"$2>
<}'>

当我们执行eval $cmd时,上面的部分由eval生成并重新组合并评估。不用说,你不希望你的命令语法像这样被分割和重新组合;谁知道会出现什么样的隐藏错误。你现在拥有的命令可能还可以,但作为通用的命令调度机制,它是有缺陷的。

【讨论】:

  • 谢谢!在原始脚本中,我在功能上将该值作为字符串传递。我不知道字符串拆分,并将记住这一点。
猜你喜欢
  • 1970-01-01
  • 2012-05-31
  • 2022-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-18
  • 2020-08-24
  • 1970-01-01
相关资源
最近更新 更多