8

我实际上是在尝试实现一个函数,该函数断言另一个命令的失败(非零退出代码),并在失败时打印一条消息。

这是我的功能:

function assert_fail () {
    COMMAND=$@
    if [ `$COMMAND; echo $?` -ne 0 ]; then 
        echo "$COMMAND failed as expected."
    else
        echo "$COMMAND didn't fail"
    fi
}

# This works as expected
assert_fail rm nonexistent

# This works too
assert_fail rm nonexistent nonexistent2

# This one doesn't work
assert_fail rm -f nonexixtent

一旦我向命令添加选项,它就不起作用。这是上面的输出:

rm: cannot remove `nonexistent': No such file or directory
rm nonexistent failed as expected.
rm: cannot remove `nonexistent': No such file or directory
rm: cannot remove `nonexistent2': No such file or directory
rm nonexistent nonexistent2 failed as expected.
rm -f nonexistent didn't fail

我尝试在命令周围加上双引号,但无济于事。我希望上面的第三次调用产生与其他两个类似的输出。

我感谢任何/所有帮助!

4

2 回答 2

12

@rici 正确指出了您所看到的问题,但您的包装函数存在一些实际问题。首先,它不能正确地保留参数中的空格(和其他一些有趣的字符)。COMMAND=$@(或COMMAND="$@")将所有参数合并为一个字符串,从而失去参数之间的空格和参数中的空格之间的区别。为了使它们保持直截了当,要么"$@"直接使用而不将其存储在变量中,要么将其存储为数组(COMMAND=("$@"),然后将其执行为"${COMMAND[@]}")。其次,如果该命令将任何内容打印到标准输出,它将对您的退出状态检查造成严重破坏;正如@chepner 所说,只需直接测试它。这是我建议的重写:

function assert_fail () {
    if "$@"; then 
        echo "$* didn't fail"
    else
        echo "$* failed as expected."
    fi
}

请注意,我执行 echo 命令的方式确实失去了参数中空格的区别。如果这是一个问题,请将 echo 命令替换为:

printf "%q " "$@"
echo "didn't fail"

printf "%q " "$@"
echo "failed as expected."
于 2012-10-16T03:14:03.967 回答
6

rm -f永远不会在不存在的文件上失败。它与你的包装无关。见man rm

OPTIONS
       -f, --force
              ignore nonexistent files, never prompt
于 2012-10-15T15:36:52.283 回答