子shell中

时间:2015-11-21 10:45:46

标签: shell subshell

在子shell环境中执行命令时会发生这种情况:

  1. 该命令将在当前shell execution environment

  2. 的副本中运行
  3. “影响shell环境的变量赋值和内置命令在命令完成后不会保持有效” (quote)

  4. 示例:

    #!/bin/sh
    
    export TOTO=123
    FOO=abc
    
    (mycmd)
    

    在这种情况下,mycmd将能够读取TOTO但不能读取FOO,并且mycmd实现的这两个变量值的每个更改都不会在当前shell中显示。

    但是当我们用函数做同样的事情时会发生什么?

    示例:

    #!/bin/sh
    
    export TOTO=123
    FOO=abc
    
    function (){
         echo $TOTO
         echo $FOO
         TOTO=${TOTO}456
         FOO=${FOO}def
    }
    
    (function)
    echo $TOTO
    echo $FOO
    

    结果:

    123
    abc
    123
    abc
    

    合理地,在子shell中执行的函数不能改变父shell中定义的变量的内容,另一方面,它能够不加选择地读取所有变量,即使它们没有被导出。

    有人可以用更好的方式解释这种行为吗? 一些参考文献的链接将非常受欢迎,因为我找不到任何关于它的信息。

2 个答案:

答案 0 :(得分:2)

您所观察到的与功能无关。子shell获得所有环境,甚至是未导出的变量。为了说明,我们定义两个变量:

$ alpha=123
$ export beta=456

观察子shell可以同时访问:

$ (echo $alpha $beta)
123 456

但是,如果我们开始一个新流程,它只会看到导出的变量:

$ bash -c 'echo $alpha $beta'
456

文档

man bash记录子壳如下:

  

(list)
list在子shell环境中执行(参见COMMAND   下面的执行环境)。变量赋值和内置   影响shell环境的命令不会保持有效   命令完成后返回状态是退出状态   列表。

如果我们查看" COMMAND EXECUTION ENVIRONMENT",我们发现它包含

  

由变量赋值设置的shell参数,或者是从环境中的shell父级设置或继承的shell参数。

换句话说,它包含变量是否已导出

如果我们进一步阅读,我们发现这与"一个简单的命令形成对比,而不是内置函数或shell函数。"这些命令只接收导出的变量。

答案 1 :(得分:1)

这是一个简短的答案,希望能够解释这些差异。它有两个函数myfunmyfunlocal。在myfunlocal中,totofoo都声明拥有localtoto的{​​{1}}个副本,这些副本在功能中更新时不会反映回来在脚本的主体中,虽然foo没有进行myfun重新声明,因此对localtoto的更改会反映在主体中。但是,如果在子shell中运行foo,则(myfun)toto的更改不会反映在脚本的foo正文中:

main

<强>输出

#!/bin/bash

function myfun {

    printf "\n               myfun - toto : %-6s  foo : %s\n" \
    "$toto" "$foo"

    toto=lizard
    foo=456

    printf "               myfun - toto : %-6s  foo : %s\n" \
    "$toto" "$foo"
}

function myfunlocal {

    printf "\n          myfunlocal - toto : %-6s  foo : %s\n" \
    "$toto" "$foo"

    local toto=lizard
    local foo=456

    printf "          myfunlocal - toto : %-6s  foo : %s\n" \
    "$toto" "$foo"
}

toto=dog
foo=123

printf "\n before myfunlocal   : toto : %-6s  foo : %s\n" "$toto" "$foo"

myfunlocal

printf "\n after myfunlocal    : toto : %-6s  foo : %s\n" "$toto" "$foo"

(myfun)

printf "\n after subshell myfun: toto : %-6s  foo : %s\n" "$toto" "$foo"

myfun

printf "\n after simple myfun  : toto : %-6s  foo : %s\n\n" "$toto" "$foo"