• 子shell


    http://bbs.csdn.net/topics/392292455

    https://www.cnblogs.com/daniaoge/p/6161821.html

    http://blog.csdn.net/qq_20327293/article/details/50425737

    1.

    如果需要使用父Shell来执行此脚本,可以使用:

    命令行:. ./test.sh

    注意.与./之间有一个空格符





    子Shell继续开启子Shell

    与父Shell启动子Shell方式一样,继续调用下去,即子Shell开启子Shell。

    通过$SHLVL变量,可以知道当前所在Shell的层次

    2.

    linux 对 反斜线 ··会fork 出一个子进程。 unix 则不会 fork 子进程。

    在一对括号 (...) 里可以放置一组指令,这些指令是在一个子 shell 里执行的。在子 shell 里的变量不能被这段子 shell 外的代码直接访问,也就是说子 shell 里的变量不能被父 shell 所存取,实际上它们是局部变量。
    这里可以参考:(( ))和 [[ ]] 和 shell 与 命令的执行 这两篇文章。

    ############sampe 1:

    父Shell与子Shell

    Login Shell

    登录主机后,在执行Bash Script之前,其实我们已经处于一个BashShell中。

    这个Shell叫login Shell,是将来我们执行任何Script的上层环境。又叫父SHell



    其实每个帐号都可以自定义loginShell。以Linux来说,帐号的login Shell定义在/etc/passwd这个文件中。

    /etc/passwd的每一行代表一个帐号,共有7个字段,之间用:隔开。

    帐号:x:UID 使用者代码:GID 群组代码:用户信息:主目录:login shell路径

    第二栏x为密码栏,基于系统安全考虑,编码后的密码已经被放入/etc/passwd文件中。

    login Shell定义在第7个字段,如果这个字段的Shell程序不存在、不合法,或执行失败,则无法登录主机。



    父Shell、子Shell

    当在执行一个Shell Script时,父Shell会根据Script程序的第一行#!之后指定的Shell程序开启一个子Shell环境,然后在子Shell中执行此Shell Script。一旦子Shell中的Script执行完毕,此子Shell随即结束,回到父Shell中,不会影响父Shell原本的环境。

    子Shell环境拥有与父Shell相同的环境变量、标准输入、输出、错误等。



    例如:

    test.sh文件内容

    #!/bin/bash

    cd /var/www/html



    命令行:chmod +x /test.sh

    命令行:./test.sh

    执行完脚本后还原到父Shell,并且父Shell并没有进入/var/www/html目录。

    注:这是因为当执行Shell文件时,父Shell会创建子Shell,各自独立。



    如果需要使用父Shell来执行此脚本,可以使用:

    命令行:. ./test.sh

    注意.与./之间有一个空格符





    子Shell继续开启子Shell

    与父Shell启动子Shell方式一样,继续调用下去,即子Shell开启子Shell。

    通过$SHLVL变量,可以知道当前所在Shell的层次

    #############sampe 2

    linux 对 反斜线 ··会fork 出一个子进程。 unix 则不会 fork 子进程。

    在一对括号 (...) 里可以放置一组指令,这些指令是在一个子 shell 里执行的。在子 shell 里的变量不能被这段子 shell 外的代码直接访问,也就是说子 shell 里的变量不能被父 shell 所存取,实际上它们是局部变量。
    这里可以参考:(( ))和 [[ ]] 和 shell 与 命令的执行 这两篇文章。

    下面用一段代码进行测试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #!/bin/bash
     
    echo "Subshell level = $BASH_SUBSHELL"
     
    outer_variable=Outer
    outer_variable2=Outer2
     
    (
     echo "Subshell level INSIDE subshell = $BASH_SUBSHELL"
     inner_variable=Inner
     outer_variable2=Outer_var_changein_subshell
     echo "From Subshell,"inner_variable"=$inner_variable"
     echo "From parent shell,"outer"=$outer_variable"
     echo "From parent shell, "outer"=$outer_variable2"
    )
     
    echo "In parent shell, check "outer_variable" value:$outer_variable"
    echo "In parent shell, check "outer_variable2" value:$outer_variable2"
     
    echo
    echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL"
    echo
     
    if [ -z "$inner_variable" ]
    then
        echo "inner_variable undefined in main body of shell"
    else
        echo "From main body of shell,"inner_variable"=$inner_variable"
    fi
     
    exit 0


    运行输出:

    引用
    beyes@debian:~/shell$ ./subshell.sh
    Subshell level = 0
    Subshell level INSIDE subshell = 1
    From Subshell,"inner_variable"=Inner
    From parent shell,"outer"=Outer
    From parent shell, "outer"=Outer_var_changein_subshell
    In parent shell, check "outer_variable" value:Outer
    In parent shell, check "outer_variable2" value:Outer2

    Subshell level OUTSIDE subshell = 0

    inner_variable undefined in main body of shell


    在上面的代码中,BASH_SUBSHELL 是一个环境变量,它表示进入子 shell 的层级,比如处于当前 shell 时,该变量值为 0;当在当前 shell 派生的子 shell 里时,该变量值为 1;如果该子 shell 又派生出一个子 shell,那么该变量在此间的值就为 3,以此类推。

    在代码中,( ) 里的代码段是在子 shell 里执行的,而 inner_variable 作为局部变量,它的值可以在 ( ) 这段代码里 echo 出来,但是一旦返回到父shell 时,它就是未定义的,所以会输出“ inner_variable undefined in main body of shell”。也就是说,局部变量不能被外部代码所访问。

    从输出可以看到,在子 shell 中和父 shell 中变量 outer_variable 的输出值是一样的;相对应的 outer_variable2 变量即使在子 shell 中进行了修改,但是当返回到父 shell 对其输出时,它却还是父 shell 中原来所赋的值。从这里可以看出,子 shell 可以 “感知” 父 shell 中的变量,但它不能修改它。其本质的原因和 fork() 函数的原理有关。在 UNIX/LINUX 中,fork 出来的子进程实际上是对父进程的一种拷贝,而子 shell 就是父shell fork 出来的一个子进程,所以它理所当然的有了父shell 中的一片拷贝。所以,子 shell 里的 outer_variable 和 outer_variable2 变量虽然和父 shell 的同名,但它们并不是同一个变量,而是父 shell 里的一个副本。

    说到父shell 和 子 shell,那么会想到 export 这个命令。export 也是 bash 的一个内置命令。它主要是用来将父 shell 里的变量导出供子 shell 使用。它有如下特征:
    1. 用 export 导出的变量放在“导出变量列表”中,它可以被子 shell (子 shell 的子 shell 也是如此)拷贝并使用。
    2. 被 export 出来的变量虽然可以被子 shell 使用,但它也只是一个拷贝,而不会影响到父 shell 中的值以及其它子 shell 中的值。

    看下面示例;

    1. 先在当前 shell 里 export 一个变量:

    引用
    beyes@debian:~/shell$ export exp8temp="hello world"
    beyes@debian:~/shell$ echo $exp8temp
    hello world



    2. 运行一个脚本 echo 此变量(该脚本只有一句话即 echo $exp8temp ):

    引用
    $ ./exp8.sh 
    hello world


    由上可见,父 shell 里 export 的变量可以被子 shell 读取。

    3. 测试一下子 shell 更改此变量是否会影响父 shell 里的值,子 shell 代码如下:

    1
    2
    3
    4
    5
    #!/bin/bash
     
    exp8temp="hello shell"
     
    echo $exp8temp


    检验上面的情景:

    引用
    beyes@debian:~/shell$ ./exp8.sh 
    hello shell
    beyes@debian:~/shell$ echo $exp8temp
    hello world


    可见子 shell 对父 shell 里 export 出来的变量进行修改并不能影响到父 shell。这说明了,子 shell 只是在“导出变量列表“里对该变量进行了一个拷贝。但反过来,父shell再次更改此变量时,子 shell 再去读时,读到的是新值,而不是原来的值。

    4. 如果在子 shell 里 export 出的变量,父 shell 是否能读到呢?
    先将下面一段代码放在后台运行:

    1
    2
    3
    4
    5
    6
    7
    #!/bin/bash
     
    export exp9temp="hello world"
     
    sleep 30
     
    exit 0


    然后在在 30 秒内在父 shell 里读取一下 $exp9temp 的值,发现输出为空。所以我们得出结论,export 出来的变量不能导出到父进程或者是父进程的环境里。一个自己称可以继承父进程的东西,而不能反过来去影响父进程。

    那么子 shell 有什么办法可以向父 shell 传递自己的变量吗?下面方法可以考虑:

    1. 通过一个中间文件进行:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/bin/bash
     
    (
     subvar="hello shell"
     echo "$subvar" > temp.txt
    )
     
    read pvar < temp.txt
     
    echo $pvar


    运行输出:

    引用
    $ sh subandp.sh 
    hello shell



    2. 通过命令替换:

    引用
    #!/bin/bash

    pvar=`subvar="hello shell";echo $subvar`

    echo $pvar


    运行输出:

    引用
    $ ./subandp.sh 
    hello shell


    执行命令替换符(两个反单引号)之间的命令也是在子 shell 来完成的。

    3. 使用命名管道:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #!/bin/bash
     
    mkfifo -m 777 npipe
     
    (
      subsend="hello world"
      echo "$subsend" > npipe &
     )
     
    read pread < npipe
     
    echo "$pread"
     
    exit 0


    运行输出:

    引用
    beyes@debian:~/shell$ ./var.sh 
    hello world


    关于有名管道创建命令 mkfifo 可参考:http://www.groad.net/bbs/read.php?tid-3707.html

    4. 使用 here 文档:

    1
    2
    3
    4
    5
    6
    7
    8
    #!/bin/bash
     
    read pvar << HERE
    `subvar="hello shell"
    echo $subvar`
    HERE
     
    echo $pvar


    运行输出:

    引用
    $ ./subandp.sh 
    hello shell



    方法应该还有很多,这些方法的本质原理基于进程间的通信。

  • 相关阅读:
    [转载]c++转python
    [转载]One-hot编码
    [转载]各种机器学习算法的应用场景
    SVC和SVR
    机器学习-正则化+回归与分类辨析
    C#编译时,提示缺少NuGet包
    C++中 左值和右值的区别
    C++11并发编程实战 免费书籍
    静态库和动态库
    C++中string类
  • 原文地址:https://www.cnblogs.com/feiyun8616/p/7930491.html
Copyright © 2020-2023  润新知