如何在变量中获取 bash 命令的输出

Posted

技术标签:

【中文标题】如何在变量中获取 bash 命令的输出【英文标题】:How to get output of a bash command in a variable 【发布时间】:2012-09-26 03:35:54 【问题描述】:

我一直在关注一些类似的问题(例如How to set a variable to the 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 变量保持为空的常见原因是什么?

【问题讨论】:

【参考方案1】:

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

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)。

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

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

希望这会有所帮助 =)

【讨论】:

嗨 Janito,非常感谢您的回答!我知道三个标准流和重定向运算符,但到目前为止我使用它们的唯一原因是将所有内容从命令发送到 /dev/null 或日志文件。我什至没有考虑这里的不同流。 $file 变量实际上是在引号中的,我在测试脚本的错误捕获功能时将其从引号中取出,以强制出错。再次,非常感谢! 我想知道为什么我的脚本不起作用。 2>&1 为我成功了。谢谢【参考方案2】:

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

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

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

【讨论】:

嗨 antak,我只想说非常感谢您的回答。由于 Janito 的更详细一点,我将其作为已接受的答案,但我非常感谢您的帮助:)。【参考方案3】:

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

【讨论】:

谢谢威廉。在这种情况下,我不想默默地成功,但如果我正在编写一个用于分发或大多数其他目的的包,我会同意。不过,这是内部软件,与实际移动文件一样重要的是,它保留了非常清晰的被触摸内容的详细信息(很多被移动的内容是敏感或关键数据)。我还需要 FATAL ERROR 前缀 - 日志文件由机器运行,数据被复制以查找该前缀或其他一些行前缀。不过再次感谢!

以上是关于如何在变量中获取 bash 命令的输出的主要内容,如果未能解决你的问题,请参考以下文章

如何在不创建子外壳的情况下将命令的输出存储在变量中 [Bash <v4]

如何在环境变量中捕获bash命令组(花括号)的输出

bash shell如何获取到命令执行结果的值?

Bash:如何在使用微调器时获取命令的退出代码?

如何在bash脚本中运行curl并将结果保存在变量中[重复]

Bash shell:如何从变量值重新格式化字符串日期