有一种非常丑陋的捕捉方式stderr
and stdout
在没有临时文件的两个单独的变量中(如果您喜欢管道),使用流程替代 http://www.gnu.org/software/bash/manual/bashref.html#Process-Substitution, source
, and declare
适当地。我会呼叫你的命令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
,终端上显示的标准错误。
Then:
{ bout=$(banana); } 2>&1
仍将分配给bout
的标准输出banana
,但是标准错误banana
通过 stdout 显示在终端上(感谢重定向2>&1
.
Then:
{ bout=$(banana); } 2>&1; declare -p bout >&2
将按照上面的方式执行,但也会在终端上显示(通过 stderr)的内容bout
与declare
内置:这将很快被重用。
Then:
berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr
将分配给berr
标准错误banana
并显示内容berr
with 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
将通过标准输出显示先前的内容。
最后,我们使用一个流程替代 http://www.gnu.org/software/bash/manual/bashref.html#Process-Substitution to source这些行的内容。
您提到了命令的返回码。改变banana
to:
banana() {
echo "banana to stdout"
echo >&2 "banana to stderr"
return 42
}
我们还将获得以下返回码banana
在变量中bret
像这样:
. <({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)
您无需采购和流程替代即可使用eval
也是(它也适用于 Bash
eval "$({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)"
而这一切都是安全的,因为我们唯一拥有的东西source
ing or eval
ing 获得自declare -p
并且总是会被正确地转义。
当然,如果您想要数组中的输出(例如,使用mapfile
,如果您使用的是 Bash≥4 — 否则替换mapfile
with a while
–read
循环),适应很简单。
例如:
banana() {
printf 'banana to stdout %d\n' {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)