2011-04-22 55 views
8

编辑:管子的左侧是子壳?

下面关于sed '[email protected]^@ @' <(f1)我的评论是不正确 虽然$BASH_SUBSHELL表明我们是在同一水平发射,变量在主脚本丢失。 基于戈登答案我测试了f1 > >(sed '[email protected]^@ @')而不是这似乎工作正常。但是,对于第一种形式,不应该BASH_SUBSHELL为1而不是0?


考虑这个小测试

#!/bin/bash 
declare -i i=0 
function f1() 
{ 
    let i++ 
    echo "In f1, SUBSHELL: $BASH_SUBSHELL, i=$i" >&2 
} 

f1 
f1 | sed '[email protected]^@  @' 

echo "at end, i=$i" 

与下面的输出:

In f1, SUBSHELL: 0, i=1 
In f1, SUBSHELL: 1, i=2 
at end, i=1 

(该sed的目的只是为了有一个管的东西,不要指望它做任何事情,因为f1输出到stderr)

函数f1记录当前的BASH_SUBSH ELL和我

我知道为什么在脚本的末尾,我们得到i=1的电流值,其因为第二次调用是在一个子shell,我在壳层1的值丢失。

什么我不知道的是,为什么管的左侧在当前shell

虽然我想,我可以sed '[email protected]^@ @' <(f1) 我想避免这种情况知道为什么左侧是未执行与主脚本不在同一级别

+0

我觉得shell允许在子shell中有管道的两端 – sehe 2011-04-22 22:32:54

+0

快速谷歌发现这个:http://www.linuxprogrammingblog.com/pipe-in​​-bash-can-be-a-trap – 2011-04-22 22:37:28

+0

@布赖恩那篇文章没有讨论管道的左侧...我已经知道这对管道右侧的变量赋值是个坏消息 – nhed 2011-04-22 22:51:54

回答

12

bash man page:“流水线中的每个命令都作为单独的进程执行(即在子shell中)。”我猜想可以在当前shell中执行管道的一个组件(即第一个,也可以是最后一个,也可能是中间的一个),但它不会像这样播放收藏夹:它们都在子壳体中执行全部 。如果您修改剧本是这样的:

#!/bin/bash 
declare -i i=0 
function f1() 
{ 
    let i++ 
    echo "In f1, SUBSHELL: $BASH_SUBSHELL, i=$i" >&2 
} 

f1 
f1 | f1 | f1 

echo "at end, i=$i" 

它打印:

In f1, SUBSHELL: 0, i=1 
In f1, SUBSHELL: 1, i=2 
In f1, SUBSHELL: 1, i=2 
In f1, SUBSHELL: 1, i=2 
at end, i=1 

,因为所有3调用F1的子shell中的管道运行。

+0

我想我的困惑来自管道和文件重定向的想法有点相同'f1 nhed 2011-04-22 23:14:18

+0

@nhed:我不会想到像输出重定向的管道。管道是由I/O重定向串联在一起的一系列命令,并且全部同时运行;由于shell不会执行多任务,因此它可以在主shell中运行其中的大部分任务,并且因为它们基本相同,所以没有理由选择一个在主shell中运行,所以为了公平,它们都是在子壳中运行。在bash中,你可以使用'< <()' and '>>()'将一些命令显式地放到子shell中,允许一个命令在主shell中运行。 – 2011-04-23 04:42:55

+3

@nhed :(继续)例如,强制管道中的第一个命令在主shell中运行,使用'cmd1 >>>(cmd2 | cmd3 | ...)''。要在主shell中运行cmd2,使用'cmd2 < <(cmd1) >>(cmd3 | ...)'等。 – 2011-04-23 04:45:53

-1

这是一个非常简洁的例子,如果有人关心:

cd/&& cd /tmp/ | pwd ; pwd 
/
/

或者:

cd/&& cd /tmp/ | cd /var/ ; pwd 
/

是这个页面说,这一切

http://linux.die.net/man/1/bash#管道中的每个命令都作为执行单独的过程(即在一个子壳中)。