我认为您想要 capture 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
此脚本捕获stderr
.stdout
和exitcode
.
但是 Teo 它是如何工作的呢?
首先,我们捕获 thestdout
和exitcode
using printf '\0%s\0%d\0'
。它们由\0
aka 'null byte'分隔。
之后,我们通过做重定向printf
到:然后我们将所有重定向回使用。因此,将看起来像:stderr
1>&2
stdout
2>&1
stdout
"<stderr>\0<stdout>\0<exitcode>\0"
将printf
命令包含在<( ... )
执行进程替换中。进程替换允许使用文件名引用进程的输入或输出。这意味着<( ... )
将使用第一个. stdout
_(printf '\0%s\0%d\0' "$(some_command_with_err)" "${?}" 1>&2) 2>&1
stdin
<
然后,我们stdout
可以stdin
使用read
. 此命令从文件描述符中读取一行stdin
并将其拆分为字段。只有在 中找到的字符$IFS
被识别为单词分隔符。$IFS
或内部字段分隔符是一个变量,它决定 Bash 在解释字符串时如何识别字段或单词边界。$IFS
默认为空格(空格、制表符和换行符),但可以更改,例如,解析逗号分隔的数据文件。请注意,$*
使用 $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'
(newline) 定义为分隔符的原因。我们的脚本使用read -r -d ''
, whereread -r
不允许反斜杠转义任何字符,并-d ''
继续直到''
读取第一个字符,而不是换行符。
最后,替换some_command_with_err
为您的脚本文件,您可以捕获和处理stderr
,stdout
以及exitcode
您的意愿。