我认为你想要捕获stderr, stdout和exitcode,如果这是你的意图,你可以使用这段代码:
## Capture error when 'some_command() is executed
some_command_with_err() {
echo 'this is the stdout'
echo 'this is the stderr' >&2
exit 1
}
run_command() {
{
IFS=$'\n' read -r -d '' stderr;
IFS=$'\n' read -r -d '' stdout;
IFS=$'\n' read -r -d '' stdexit;
} < <((printf '\0%s\0%d\0' "$(some_command_with_err)" "${?}" 1>&2) 2>&1)
stdexit=${stdexit:-0};
}
echo 'Run command:'
if ! run_command; then
## Show the values
typeset -p stdout stderr stdexit
else
typeset -p stdout stderr stdexit
fi
这个脚本捕获标准错误、标准输出以及退出代码。
但是Teo它是如何工作的呢?
首先,我们使用printf '\0%s\0%d\0'捕获标准输出和退出代码。它们由\0分隔,也就是“空字节”。
在此之后,我们通过执行:1>&2将printf重定向到stderr,然后使用2>&1将所有重定向回stdout。因此,标准输出看起来像:
"<stderr>\0<stdout>\0<exitcode>\0"
将printf命令封装在<(…)执行流程替换。进程替换允许使用文件名引用进程的输入或输出。这意味着<(…)将输出(printf '\0%s\0%d\0' "$(some_command_with_err)"“$ {?}" 1>&2) 2>&1到命令组的stdin中使用第一个<。
Then, we can capture the piped stdout from the stdin of the command group with read. This command reads a line from the file descriptor stdin and split it into fields. Only the characters found in $IFS are recognized as word delimiters. $IFS or Internal Field Separator is a variable that determines how Bash recognizes fields, or word boundaries, when it interprets character strings. $IFS defaults to whitespace (space, tab, and newline), but may be changed, for example, to parse a comma-separated data file. Note that $* uses the first character held in $IFS.
## Shows whitespace as a single space, ^I(horizontal tab), and newline, and display "$" at end-of-line.
echo "$IFS" | cat -vte
# Output:
# ^I$
# $
## Reads commands from string and assign any arguments to pos params
bash -c 'set w x y z; IFS=":-;"; echo "$*"'
# Output:
# w:x:y:z
for l in $(printf %b 'a b\nc'); do echo "$l"; done
# Output:
# a
# b
# c
IFS=$'\n'; for l in $(printf %b 'a b\nc'); do echo "$l"; done
# Output:
# a b
# c
这就是为什么我们将IFS=$'\n'(换行符)定义为分隔符。
我们的脚本使用read -r -d ",其中read -r不允许反斜杠转义任何字符,并且-d "继续直到读取第一个字符",而不是换行符。
最后,用你的脚本文件替换some_command_with_err,你就可以捕获和处理stderr、stdout以及exitcode了。