在bash中的复合命令中设置变量失败(命令组)
group命令在bash中的复合命令中设置变量失败(命令组),bash,Bash,group命令{list;}应该在当前shell环境中执行list 这允许变量赋值等内容在命令组()之外可见 我使用它将输出发送到日志文件以及终端: { { echo "Result is 13"; echo "ERROR: division by 0" 1>&2; } | tee -a stdout.txt; } 3>&1 1>&2 2>&3 | tee -a stderr.txt; 关于主题“在shell脚本中将stdout和stde
{list;}
应该在当前shell环境中执行list
这允许变量赋值等内容在命令组()之外可见
我使用它将输出发送到日志文件以及终端:
{ { echo "Result is 13"; echo "ERROR: division by 0" 1>&2; } | tee -a stdout.txt; } 3>&1 1>&2 2>&3 | tee -a stderr.txt;
关于主题“在shell脚本中将stdout和stderr管道连接到两个不同的进程?”请阅读以下内容:
模拟输出到stdout和stderr的命令
我还想评估退出状态/bin/true
和/bin/false
模拟可能成功或失败的命令。因此,我尝试将$?
保存到变量r
:
~$ r=init; { /bin/true; r=$?; } | cat; echo $r;
init
~$ r=init; { /bin/true; r=$?; } 2>/dev/null; echo $r;
0
正如您所看到的,上面的管道构造没有设置变量r
,而第二个命令行导致了预期的结果。是虫子还是我的错?谢谢
我用以下版本的bash测试了Ubuntu 12.04.2 LTS(~$
)和Debian GNU/Linux 7.0(wheezy)(~#
):
~$ echo $BASH_VERSION
4.2.25(1)-release
~# echo $BASH_VERSION
4.2.37(1)-release
我想,您错过了/bin/true返回0和/bin/false返回1 $r='res:';{/bin/true;r+=$?;}2>/dev/null;echo$r res:0 及 $r='res:';{/bin/false;r+=$?;}2>/dev/null;echo$r 决议:1
我尝试了一个测试程序:
x=0
{ x=$$ ; echo "$$ $BASHPID $x" ; }
echo $x
x=0
{ x=$$ ; echo "$$ $BASHPID $x" ; } | cat
echo $x
事实上,管道似乎将先前的代码强制进入另一个进程,但没有重新初始化bash,因此$BASHPID
发生了变化,但$
发生了变化
有关$
和$BASHPID
之间差异的更多详细信息,请参阅
同时输出
$BASH_SUBSHELL
显示第二位在子shell(级别1)中运行,第一位在级别0处。BASH将管道的所有元素作为子进程执行;如果它们是shell内置或命令组,这意味着它们在子shell中执行,因此它们设置的任何变量都不会传播到父shell。一般来说,这可能很难解决,但如果您只需要命令组的退出状态,则可以使用$PIPESTATUS数组来获取它:
$ { false; } | cat; echo "${PIPESTATUS[@]}"
1 0
$ { false; } | cat; r=${PIPESTATUS[0]}; echo $r
1
$ { true; } | cat; r=${PIPESTATUS[0]}; echo $r
0
请注意,这仅适用于获取组中最后一个命令的退出状态:
$ { false; true; false; uselessvar=$?; } | cat; r=${PIPESTATUS[0]}; echo $r
0
。。。因为
uselessvar=$?
成功。使用变量保持退出状态对于管道来说不是合适的方法:
~$ r=init; { /bin/true; r=$?; } | cat; echo $r;
init
。。。因此,我应用了一些缩进:
{
{
: # no operation
r=$( {
{
{
echo "Result is 13"
echo "ERROR: division by 0" 1>&2
/bin/false; echo $? 1>&4
} | tee stdout.txt;
} 3>&1 1>&2 2>&3 | tee stderr.txt;
} 4>&1 1>&2 2>&3 );
} 3>&1;
} 1>stdout.term 2>stderr.term; echo r=$r
让我解释一下:
虽然
{…}
确实意味着在当前的shell环境中运行一个简单的命令,{/code>(以及某些其他构造)意味着在子shell中运行一个或多个命令,而不管它是否由{…}
或(…)
包围。我理解。Manpage正确地指出:“管道中的每个命令都作为一个单独的进程执行(即,在子shell中)。”这就是答案。感谢Douglas Leeder,他指出了如何分析关于子壳的混淆。
root@voipterm1:~# cat stdout.txt
Result is 13
root@voipterm1:~# cat stderr.txt
ERROR: division by 0
root@voipterm1:~# cat stdout.term
Result is 13
root@voipterm1:~# cat stderr.term
ERROR: division by 0
{
echo "Result is 13"
echo "ERROR: division by 0" 1>&2
/bin/false; echo $? 1>&4
} | tee stdout.txt;
{
...
} 3>&1 1>&2 2>&3 | tee stderr.txt;
r=$( {
...
} 4>&1 1>&2 2>&3 );
{
...
} 3>&1;
~# r=init; { { echo "Result is 13"; echo "ERROR: division by 0" 1>&2; } | tee -a stdout.txt; r=${PIPESTATUS[0]}; } 3>&1 1>&2 2>&3 | tee -a stderr.txt; echo "Can you tell me the exit status? $r"
ERROR: division by 0
Result is 13
Can you tell me the exit status? init