在Bash中捕获stdout和stderr
这个问题在这里已经有了答案:
没有临时文件,无法捕获两者。
您可以将stderr捕获到变量并将stdout传递到用户屏幕(从此处取样):
exec 3>&1 # Save the place that stdout (1) points to.
output=$(command 2>&1 1>&3) # Run command. stderr is captured.
exec 3>&- # Close FD #3.
# Or this alternative, which captures stderr, letting stdout through:
{ output=$(command 2>&1 1>&3-) ;} 3>&1
但是无法捕获stdout和stderr:
你不能做的是在一个变量中捕获stdout,在另一个变量中捕获stderr,只使用FD重定向。 您必须使用临时文件(或命名管道)来实现该文件。
在没有临时文件的情况下(如果您喜欢管道),使用流程替换, source
和正确declare
,捕获stderr
和stdout
方法非常糟糕。 我会打电话给你的命令banana
。 你可以用一个函数来模仿这样的命令:
banana() {
echo "banana to stdout"
echo >&2 "banana to stderr"
}
我假设你想要的标准输出banana
变量bout
和标准误差banana
变量berr
。 这就是达到这个目的的魔法(只有Bash≥4):
. <({ berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)
那么,这里发生了什么?
我们从最内层的术语开始:
bout=$(banana)
这仅仅是分配给标准的方式bout
的标准输出banana
,显示在终端上的标准误差。
然后:
{ bout=$(banana); } 2>&1
将仍然分配给bout
的标准输出banana
,但标准错误banana
经由标准输出显示在终端(由于重定向2>&1
。
然后:
{ bout=$(banana); } 2>&1; declare -p bout >&2
将做如上述,但也将在终端显示(通过stderr)上的内容bout
与declare
内置:这将很快重新使用。
然后:
berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr
将要分配给berr
的stderr的banana
和显示的内容berr
与declare
。
此时,您将在终端屏幕上显示:
declare -- bout="banana to stdout"
declare -- berr="banana to stderr"
与线
declare -- bout="banana to stdout"
通过stderr显示。
最后的重定向:
{ berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1
将通过stdout显示以前的内容。
最后,我们使用流程替换来获取这些行的内容。
你也提到了命令的返回码。 将banana
:
banana() {
echo "banana to stdout"
echo >&2 "banana to stderr"
return 42
}
我们还会在变量bret
包含banana
的返回码, bret
所示:
. <({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)
你可以通过使用eval
来完成源代码和流程替换(并且它也适用于Bash <4):
eval "$({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)"
所有这些都是安全的,因为我们唯一的source
或eval
东西是从declare -p
中获得的,并且总是会被正确地转义。
当然,如果你想在一个阵列的输出(例如, mapfile
,如果你使用Bash≥4,否则更换mapfile
用while
- read
圈),适应很简单。
例如:
banana() {
printf 'banana to stdout %dn' {1..10}
echo >&2 'banana to stderr'
return 42
}
. <({ berr=$({ mapfile -t bout < <(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)
并返回代码:
. <({ berr=$({ mapfile -t bout< <(banana; bret=$?; declare -p bret >&3); } 3>&2 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)
你可以做:
OUT=$(myscript.sh 2> errFile)
ERR=$(<errFile)
现在$OUT
将会有脚本的标准输出,而$ERR
会有脚本的错误输出。
上一篇: Capture both stdout and stderr in Bash
下一篇: What does the ampersand indicate in this bash command 1>&2