15

我一直在关注一些类似的问题(例如How to set a variable to output from a command in Bash?),但是接受的答案似乎对我不起作用。我不确定我是否应该破坏别人的问题或发布我自己的副本,所以如果我在这里选错了,请道歉。

我希望在我放在一起的脚本中获得许多命令的输出和退出状态。这是我一直在使用的示例:

cmd_output=$(rm $file)
exit_status=$?
if [ "${exit_status}" -eq 0 ]
then
log "Successfully removed the original" ${TAB_LEVEL}
else
fail "Failed to remove the original, the output was: \n ${cmd_output}"
fi

日志和失败函数是:

# Usage: fail "Failure message"
function fail {
echo "FATAL ERROR: $1" >> "${LOG_DIR}/${LOG_FILE}"
exit 1
}

# Usage: log "Log message" 3    Where the tab-level is 3.
function log {
if (("${2}" > 0))
then
eval "printf '    %.0s' {1..$2}" >> "${LOG_DIR}/${LOG_FILE}"
fi
echo "$1" >> "${LOG_DIR}/${LOG_FILE}"
return 0
}

在上面的示例中,我使用了 $(cmd) 格式,但我也尝试过使用反引号。

在我的日志文件中,出现故障时我看到的只是:

致命错误:无法删除原件,输出为:\n

此外,失败命令的输出会照常显示在屏幕上。我的 cmd_output 变量保持为空是否有一个常见原因?

4

3 回答 3

35

您必须包含特殊标准错误输出流的输出:

cmd_output=$(rm "$file" 2>&1)

每个程序都有三个默认流(即编号的文件描述符):

0. Standard input (where the program normally reads from)
1. Standard output (where the program normally writes to)
2. Standard error (where the program normally writes error messages)

$(...)因此,要捕获错误消息,我们必须将标准错误输出 (stderr) 重定向到正常的标准输出 (stdout),然后表达式将捕获该输出。

重定向的语法是通过>“运算符”。在它之前你告诉哪个文件描述符重定向(默认为 1,即标准输出)。您可以指定它以重定向到文件。如果你&在它后面写一个 & 符号 ( ),你会强制它重定向到另一个文件描述符。因此,在本例中,我们将文件描述符 2 (stderr) 重定向到文件描述符 1 (stdout)。

此外,您还可以使用<“运算符”重定向输入,但在这种情况下,默认文件描述符为 0 (stdin)。

另一个观察结果是,将$file变量放在双引号之间可能是一种好习惯,以防它包含空格字符。

希望这会有所帮助=)

于 2012-10-05T01:56:05.370 回答
6

* nix 命令一般有两种输出形式:标准输出(stdout)和标准错误(stderr)。

FOO=$(...)只捕获stdout,并且不受阻碍地离开stderr

如果你想stderr使用这种语法的内容,你需要给你的命令加上后缀,2>&1以便stderr合并到stdout. (例如像这样rm $file 2>&1:)

于 2012-10-05T02:02:16.713 回答
0

由于您的fail功能刚刚退出,因此简单地执行以下操作会容易得多:

set -e  # Abort on failure
exec 2>> "${LOG_DIR}/${LOG_FILE}"  # Append all errors to LOG_FILE
if cmd_output=$(rm $file)
  log "Successfully removed the original" ${TAB_LEVEL}
fi

此代码与原始代码之间的唯一区别是它不打印文本FATAL ERROR:log由于简洁是一种美德,完全跳过该功能可能会更好。大声报告错误;默默地成功。

于 2012-10-05T04:24:48.020 回答