【问题标题】:Grouping commands in curly braces and piping does not preserve variable花括号和管道中的分组命令不保留变量
【发布时间】:2015-06-09 09:05:25
【问题描述】:

假设我在当前工作目录中有一个文件myfile。如果命令正常执行,我想设置一个变量,但也使用它的结果。

$ ls myfile && v=3
myfile
$ echo "$v"
3

但现在我也想通过管道传输结果,所以我使用{ list; } 语法对命令进行分组:

$ 未设置 v $ { ls myfile && v=3; } | grep 我的 我的文件 $回声“$v” # v 没有设置

Bash reference manual -> 3.2.4.3 Grouping Commands 说:

{ list; }

在大括号之间放置命令列表会导致列表 在当前 shell 上下文中执行。没有创建子shell。这 列表后面的分号(或换行符)是必需的。

所以,据我了解,v 应该设置为 3。但它没有发生。为什么?

【问题讨论】:

    标签: bash


    【解决方案1】:

    导致创建子shell的不是花括号,而是管道。

    为了证明:

    $ { ls && v=3; } > tmp
    $ echo "$v"
    3
    

    引用Greg:

    在大多数 shell 中,管道的每个命令都在单独的 SubShell 中执行。

    【讨论】:

    • 哦哦,所以v=1 | echo "hi" 也是一样的情况。
    • 是的,对v 的更改只会在子shell 的生命周期内持续。
    • 是的,因为v=2; v=1 | echo "hi, v=$v" 返回“hi, v=2”。很有趣,非常感谢!
    • @fedorqui 看看我的回答here。这几乎是一回事。
    【解决方案2】:

    您可以使用BASH_SUBSHELL 变量来验证您是否在子shell 中。

    # BASH_SUBSHELL will print level of subshell from top due to pipe
    { unset v && ls file && v=3 && echo "$BASH_SUBSHELL - $v"; } | nl
         1  file
         2  1 - 3
    
    # outside BASH_SUBSHELL will print 0
    echo "$BASH_SUBSHELL - $v";
    0 -
    

    您可以使用管道命令打印1,这意味着它位于子shell 中,因此v 的值在外部不可用(从第二个输出可见)

    【讨论】:

    • 感谢你的诡计,anubhava,你总是带来一些有趣的东西:)
    • $BASHPID 也可以用来获取shell实例的真实PID。
    猜你喜欢
    • 2014-11-26
    • 1970-01-01
    • 2014-11-23
    • 2015-12-25
    • 1970-01-01
    • 1970-01-01
    • 2015-09-03
    • 2016-07-08
    • 2018-03-20
    相关资源
    最近更新 更多