dje*_*lin 41 bash stdout pipe stream stderr
我知道这个语法
var=`myscript.sh`
Run Code Online (Sandbox Code Playgroud)
要么
var=$(myscript.sh)
Run Code Online (Sandbox Code Playgroud)
将捕获结果(stdout
)myscript.sh
转化为var
.我可以重定向stderr
到stdout
,如果我想同时捕获.如何将它们中的每一个保存为单独的变量?
我在这里的用例是如果返回代码非零,我想要回显stderr
并禁止其他方式.可能有其他方法可以做到这一点,但这种方法似乎可行,如果它实际上是可能的.
gni*_*urf 44
有一个非常丑陋的方式来捕捉stderr
和stdout
在没有临时文件两个单独的参数(如果你喜欢管道),使用过程中替换,source
和declare
适当的.我会打电话给你banana
.您可以使用函数模仿这样的命令:
banana() {
echo "banana to stdout"
echo >&2 "banana to stderr"
}
Run Code Online (Sandbox Code Playgroud)
我假设你想要的标准输出banana
变量bout
的标准误差banana
的变量berr
.这是实现这一目标的魔力(仅限Bash≥4):
. <({ berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)
Run Code Online (Sandbox Code Playgroud)
那么,这里发生了什么?
让我们从最内层的术语开始:
bout=$(banana)
Run Code Online (Sandbox Code Playgroud)
这只是分配给bout
标准输出的标准方法banana
,即终端上显示的标准错误.
然后:
{ bout=$(banana); } 2>&1
Run Code Online (Sandbox Code Playgroud)
仍将分配给bout
stdout banana
,但stderr banana
通过stdout显示在终端上(由于重定向2>&1
.
然后:
{ bout=$(banana); } 2>&1; declare -p bout >&2
Run Code Online (Sandbox Code Playgroud)
将做如上述,但也将在终端显示(通过stderr)上的内容bout
与declare
内置:这将很快重新使用.
然后:
berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr
Run Code Online (Sandbox Code Playgroud)
将分配给berr
stderr banana
并显示berr
with 的内容declare
.
此时,您将在终端屏幕上看到:
declare -- bout="banana to stdout"
declare -- berr="banana to stderr"
Run Code Online (Sandbox Code Playgroud)
与线
declare -- bout="banana to stdout"
Run Code Online (Sandbox Code Playgroud)
通过stderr显示.
最后的重定向:
{ berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1
Run Code Online (Sandbox Code Playgroud)
将通过stdout显示之前的内容.
最后,我们使用一个进程替换到源这些行的内容.
你也提到了命令的返回码.更改banana
到:
banana() {
echo "banana to stdout"
echo >&2 "banana to stderr"
return 42
}
Run Code Online (Sandbox Code Playgroud)
我们还将banana
在变量中bret
包含返回代码,如下所示:
. <({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)
Run Code Online (Sandbox Code Playgroud)
您也可以不使用源代码和使用进程替换eval
(并且它也适用于Bash <4):
eval "$({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)"
Run Code Online (Sandbox Code Playgroud)
而这一切是安全的,因为只有东西我们source
荷兰国际集团和eval
荷兰国际集团从获得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)
Run Code Online (Sandbox Code Playgroud)
并带有返回码:
. <({ berr=$({ mapfile -t bout< <(banana; bret=$?; declare -p bret >&3); } 3>&2 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)
Run Code Online (Sandbox Code Playgroud)
zb'*_*zb' 29
没有临时文件就无法捕获它们.
您可以将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
Run Code Online (Sandbox Code Playgroud)
但是没有办法捕获stdout和stderr:
你不能做的是在一个变量中捕获stdout,在另一个变量中捕获stderr,仅使用FD重定向.您必须使用临时文件(或命名管道)来实现该文件.
anu*_*ava 15
你可以做:
OUT=$(myscript.sh 2> errFile)
ERR=$(<errFile)
Run Code Online (Sandbox Code Playgroud)
现在$OUT
将具有脚本的标准输出并且$ERR
具有脚本的错误输出.
一种简单但不优雅的方法:将stderr重定向到临时文件,然后将其读回:
TMP=$(mktemp)
var=$(myscript.sh 2> "$TMP")
err=$(cat "$TMP")
rm "$TMP"
Run Code Online (Sandbox Code Playgroud)
小智 7
虽然我还没有找到一种方法来捕获 stderr 和 stdout 以在 bash 中分隔变量,但我将两者发送到同一个变量 \xe2\x80\xa6
\n\nresult=$( { grep "JUNK" ./junk.txt; } 2>&1 )\n
Run Code Online (Sandbox Code Playgroud)\n\n\xe2\x80\xa6 然后我检查退出状态 \xe2\x80\x9c$?\xe2\x80\x9d,并对 $result 中的数据采取适当的操作。
\n 归档时间: |
|
查看次数: |
46571 次 |
最近记录: |