2012-10-05 30 views
7

我已经通过了一些类似的问题(如How to set a variable to the output from a command in Bash?),但是之后被接受的答案似乎不为我工作。我不确定我是否应该脱轨别人的问题或张贴我自己的副本,所以如果我在这里选择了错误,请致歉。如何获得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)格式,但我自己也尝试使用反引号。

在我的日志文件,我看到的时候有一个失败:

FATAL ERROR: Failed to remove the original, the output was: \n

此外,失败的命令的输出按通常在屏幕上结束。是否有一个共同的原因,我的cmd_output变量将保持为空?

回答

22

你必须包括特殊标准错误输出流的输出:

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) 

所以要捕获错误消息,我们必须重定向标准错误输出(错误)转换成然后将由$(...)表达被捕获正常标准输出(stdout)。

重定向的语法是通过>“经营者”。紧接着它告诉哪个文件描述符重定向(默认值是1,这是stdout)。你可以指定它重定向到一个文件。如果在它之后写一个和号(&),则会强制它重定向到另一个文件描述符。因此,在本例中,我们将文件描述符2(stderr)重定向到文件描述符1(stdout)。

此外,您还可以重定向与<“经营者”的输入,但在这种情况下,默认文件描述符0(标准输入)。

另一种看法是,它可能是很好的做法,用双引号引你$file变量,如果它有空白字符。

希望这有助于有点=)

+1

很高兴推动你超过1000分,继续发帖! – shellter

+0

嘿Janito,非常感谢您的回答!我知道三个标准流和重定向操作符,但迄今为止我使用它们的唯一原因是将所有内容从命令发送到/ dev/null或发送到日志文件。我甚至没有考虑这里的不同流。 $ file变量实际上最初是用引号引起来的,当我测试脚本的错误捕捉函数时,我把它引出来,强制出错。再次,非常感谢! –

5

* 尼克斯命令通常有两种形式的输出:标准输出(stdout)和标准误差(stderr)。

FOO=$(...)只捕获stdout,叶子stderr不受阻碍。

如果要使用此语法的stderr的内容,则需要使用2>&1后缀来修改命令,以便stderr合并到stdout中。 (例如。像这样:rm $file 2>&1

+0

嗨antak,只是想说一句谢谢你的答案。由于Janito的更详细一点,我将它作为接受的答案留下,但我非常感谢你的帮助:)。 –

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函数。大声报告错误;默默地成功 。

+0

感谢威廉。在这种情况下,我不想默默地获得成功,但如果我正在编写一个分发包或大多数其他目的的包,我会同意。这是内部软件,与移动文件实际上一样重要的是,它能够保持非常清晰的细节(被移动的是敏感或关键数据)。我还需要FATAL ERROR前缀 - 日志文件由机器运行,数据被复制到寻找那个或几个其他行前缀。 虽然再次感谢! –