【问题标题】:Run piped commands with eval使用 eval 运行管道命令
【发布时间】:2017-12-13 13:29:01
【问题描述】:

我有以下命令行来检查文件系统的可用空间:

fs_used=`df -h /u01 | sed '1d' | sed '1d' | awk '{print $4}' | cut -d'%' -f1`

它工作正常。它返回文件系统上已用空间的百分比(不带 % 符号)。

现在我需要将其设为变量并使用 eval 命令运行它。我尝试了以下方法,但它不起作用(使用 df 退出:无效选项 -- 'd')

df_cmnd="df -h $fs1 | sed '1d' | sed '1d' | awk '{print $4}' | cut -d'%' -f1"
fs_used=eval $df_cmnd

我猜,问题在于 eval 无法运行管道命令。真的吗? 是否有任何解决方法或替代方法可以使此代码运行?

【问题讨论】:

  • 不行,你需要把它变成一个函数,而不是一个变量。

标签: bash escaping pipe eval quoting


【解决方案1】:

反斜杠转义$,并使用$()

#              V                                         V
df_cmnd="df -h \$fs1 | sed '1d' | sed '1d' | awk '{print \$4}' | cut -d'%' -f1"
fs_used=$(eval "$df_cmnd")
#       ^^               ^

这将使用您评估时fs1 的值。

但是,实际上,请don't use eval!改为使用 shell 函数:

df_cmnd(){
    df -h "$1" | sed '1d' | sed '1d' | awk '{print $4}' | cut -d'%' -f1
}
fs_used=$(df_cmnd /u01)

那你就不用担心逃跑了。

说明

看看bash如何解释你的df_cmnd分配:

$ df_cmnd="df -h $fs1 | sed '1d' | sed '1d' | awk '{print $4}' | cut -d'%' -f1"
$ echo $df_cmnd
df -h | sed '1d' | sed '1d' | awk '{print }' | cut -d'%' -f1
#    ^                                   ^

在我的例子中,fs1 是空的,所以我只得到了 df -hdf 部分。在你和我的情况下,bash 用它的值替换了$4,这里是空的,因为我没有在带有四个参数的脚本中运行。因此,awk 将打印整行,而不仅仅是第四个字段。

【讨论】:

  • 非常感谢,我将使用功能选项
  • @OuldAbba 我很高兴听到这个消息! :D :D :D Less eval 让世界变得更美好。
  • 如果您曾经使用过eval,请记住将您的变量双引号(例如eval "$df_cmnd")。这消除了一整类奇怪的eval 相关的错误。 (不幸的是,它并没有修复其他十几个与eval 相关的怪异错误。所以你仍然应该避免eval。)
  • @GordonDavisson 好点 - 已编辑。虽然我对展示如何使用eval“正确”感到复杂;)
【解决方案2】:

我确实需要eval-ing 一个字符串:一个辅助脚本运行一个复杂的管道序列,带有双引号(例如--json-override='"key": "value"'),长度为 460+ 个字符。但是当我使用--noop 运行它时,我想查看将要执行的命令,以可复制粘贴的形式手动执行。我想出了这个:

echo_eval () {
    cmd=$(cat)
    if ((noop)); then
        echo "$cmd"
    else
        eval "$cmd"
    fi
}

foo () { for arg; do echo "[$arg]"; done; }

echo_eval <<EOF
foo 1 2 "3 4" '"5 6"' " 7 " "\"8 9\"" | tac
EOF
exit 1

here-document 的主要目的是跳过在已经被 ' 或 " 引用的字符串中使用 ' 和 " 引号的所有陷阱(痛苦和痛苦)。

虽然我没有对它进行广泛的测试,但它似乎点击了相关的复选框,如管道、引用、引用包含空格的参数、保留引用的引号、转义的引号、参数中的前导/尾随空格等:

["8 9"]
[ 7 ]
["5 6"]
[3 4]
[2]
[1]

noop 为真时,我得到:

foo 1 "2" "3 4" '"5 6"' " 7 " "\"8 9\"" | tac

这是逐字命令,可复制粘贴以供手动执行并产生相同的输出。

我们也可以使用&lt;&lt;'EOF'来禁用echo_eval之前的任何$s的替换,但是如果在调用echo_eval之前确实需要进行任何变量/命令替换,我们必须使用&lt;&lt;EOF并转义之前不应评估的所有 $s。


说了这么多,我很乐意 (a) 了解是否存在陷阱(除了上面提到的 $),并且 (b) 如果存在问题,请找到更好的解决方案。

【讨论】:

    最近更新 更多