我知道这句法
var=`myscript.sh`
要么
var=$(myscript.sh)
将捕捉到的结果( stdout
的) myscript.sh
成var
。 我可以重定向stderr
到stdout
,如果我想同时捕获。 如何他们每个人保存到不同的变量?
我在这里的使用情况是,如果返回代码为非零我想呼应stderr
和抑制其他。 可能还有其他方法可以做到这一点,但这种做法似乎它会工作,如果它实际上是可能的。
有没有办法不用临时文件,以同时捕获。
您可以捕获标准错误变量和(从样品通过标准输出到用户屏幕在这里 ):
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在另一个,只用FD重定向。 您必须使用一个临时文件(或命名管道)来实现的那一个。
有一个非常丑陋的方式来捕捉stderr
和stdout
中没有临时文件两个单独的参数(如果你喜欢管道),使用过程中替换 , source
,并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
,显示在终端上的标准误差。
然后:
{ 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
将通过标准输出显示前面。
最后,我们使用一个进程替换到源这些行的内容。
你提到的命令的返回码了。 更改banana
到:
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 <4太作品):
eval "$({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)"
而这一切是安全的,因为只有东西我们是source
ING或eval
从获得ING declare -p
而且将永远是正确转义。
当然,如果你想在一个阵列的输出(例如, mapfile
,如果你使用Bash≥4,否则更换mapfile
用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)
你可以做:
OUT=$(myscript.sh 2> errFile)
ERR=$(<errFile)
现在$OUT
将有脚本的标准输出和$ERR
有脚本的错误输出。
一个简单的,但不是优雅的方式:stderr重定向到一个临时文件,然后读出来:
TMP=$(mktemp)
var=$(myscript.sh 2> "$TMP")
err=$(cat "$TMP")
rm "$TMP"
虽然我还没有找到一种方法来捕获stderr和标准输出到在bash独立变量,我同时发送给使用同一个变量...
result=$( { grep "JUNK" ./junk.txt; } 2>&1 )
...然后我检查退出状态“$?”,并在$结果的数据采取适当的行动。
# NAME
# capture - capture the stdout and stderr output of a command
# SYNOPSIS
# capture <result> <error> <command>
# DESCRIPTION
# This shell function captures the stdout and stderr output of <command> in
# the shell variables <result> and <error>.
# ARGUMENTS
# <result> - the name of the shell variable to capture stdout
# <error> - the name of the shell variable to capture stderr
# <command> - the command to execute
# ENVIRONMENT
# The following variables are mdified in the caller's context:
# - <result>
# - <error>
# RESULT
# Retuns the exit code of <command>.
# SOURCE
capture ()
{
# Name of shell variable to capture the stdout of command.
result=$1
shift
# Name of shell variable to capture the stderr of command.
error=$1
shift
# Local AWK program to extract the error, the result, and the exit code
# parts of the captured output of command.
local evaloutput='
{
output [NR] = $0
}
END \
{
firstresultline = NR - output [NR - 1] - 1
if (Var == "error") \
{
for (i = 1; i < firstresultline; ++ i)
{
printf ("%s\n", output [i])
}
}
else if (Var == "result") \
{
for (i = firstresultline; i < NR - 1; ++ i)
{
printf ("%s\n", output [i])
}
}
else \
{
printf ("%d", output [NR])
}
}'
# Capture the stderr and stdout output of command, as well as its exit code.
local output="$(
{
local stdout
stdout="$($*)"
local exitcode=$?
printf "\n%s\n%d\n%d\n" \
"$stdout" "$(echo "$stdout" | wc -l)" "$exitcode"
} 2>&1)"
# extract the stderr, the stdout, and the exit code parts of the captured
# output of command.
printf -v $error "%s" \
"$(echo "$output" | gawk -v Var="error" "$evaloutput")"
printf -v $result "%s" \
"$(echo "$output" | gawk -v Var="result" "$evaloutput")"
return $(echo "$output" | gawk "$evaloutput")
}