运行 带有 eval 的管道命令

Run piped commands with eval

我有以下命令行来检查文件系统的空闲 space:

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

它工作正常。它 returns 已用 space 在文件系统上的百分比(没有 % 符号)。

现在我需要使用 eval 命令 使其成为可变的 运行。我尝试了以下但它不起作用(使用 df 退出:无效选项 -- 'd')

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

我猜,问题是 eval 不能 运行 管道命令。真的吗? 是否有任何解决方法或替代方法来制作此代码 运行?

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

#              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 "" | sed '1d' | sed '1d' | awk '{print }' | cut -d'%' -f1
}
fs_used=$(df_cmnd /u01)

那就不用担心转义了

说明

看看 bash 如何解释你的 df_cmnd 作业:

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

在我的例子中,fs1 是空的,所以我只得到 df 部分的 df -h。在您和我的情况下,bash 将 替换为它的值,此处为空,因为我不是 运行 在具有四个参数的脚本中。因此,awk 将打印整行而不仅仅是第四个字段。

我有合法需要 eval-ing 一个字符串:一个助手脚本 运行s 一个复杂的管道序列,带有双引号(例如 --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

此处文档的主要目的是跳过在已经用 ' 或 " 引用的字符串中使用 ' 和 " 引号的所有陷阱(痛苦和痛苦)。

虽然我没有对其进行广泛的测试,但它似乎选中了相关的复选框,例如管道、引用、引用包含 space 的参数、保留引号、转义引号、leading/trailing space 参数等:

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

noop 为真时,我得到:

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

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

我们还可以使用 <<'EOF' 禁用 echo_eval 之前的任何 $ 替换,但是如果任何 variable/command 替换确实需要在调用 [=19 之前发生=],我们必须使用 <<EOF 并转义之前不应该计算的所有 $


说了这么多,我很乐意 (a) 听听是否有陷阱(除了上面提到的 $)和 (b) 如果有的话,找到更好的解决方案。