使用eval运行管道命令

时间:2017-12-13 13:29:02

标签: bash escaping pipe eval quoting

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

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无法运行管道命令。真的吗? 是否有任何解决方法或替代方法来运行此代码?

2 个答案:

答案 0 :(得分:7)

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

#              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 -h部分获得了df。在你和我的情况下,bash将$4替换为其值,此处为空,因为我没有在带有四个参数的脚本中运行。因此,awk将打印整行,而不仅仅是第四个字段。

答案 1 :(得分:1)

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

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

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

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

noop为真时,我得到:

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

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

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


已经说了这么多,我很高兴(a)听到是否存在陷阱(除了上述$之外),并且(b)如果有问题,则可以找到更好的解决方案。