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

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

子shell的更多相关文章

  1. 统计文件种类数+获取子shell返回值的其它方法

    前言 只是作为一个shell的小小练习和日常统计用,瞎折腾的过程中也是摸到了获取子shell返回值的几种方法: 肯定还有别的方法,跟进程间的通信相关,希望你能提出建议和补充,谢谢~ 完整程序: #! ...

  2. 命令行子shell 括号 ()

    子shell 控制变量 ansible-direc:~ # (export hello=world;echo $hello)worldansible-direc:~ # echo $hello ans ...

  3. Linux Shell编程(27)——子shell

    运行一个shell脚本时会启动另一个命令解释器. 就好像你的命令是在命令行提示下被解释的一样, 类似于批处理文件里的一系列命令.每个shell脚本有效地运行在父shell(parent shell)的 ...

  4. 进入子shell的各种情况分析

    子shell的概念贯穿整个shell,写shell脚本时更是不可不知.所谓子shell,即从当前shell环境新开一个shell环境,这个新开的shell环境就称为子shell(subshell),而 ...

  5. Linux编程 9 (shell类型,shell父子关系,子shell用法)

    一. shell类型 1.1  交互式 bin/ shell程序 当用户登录到某个虚拟控制台终端或是在GUI中启动终端仿真器时,默认的shell程序就会开始运行.系统启动什么样的shell程序取决于你 ...

  6. Linux中shell和子shell一点点理解

    Linux执行脚本有两种方式,主要区别在于是否建立子shell   1.像sh,bash,./命令是用来执行shell脚本的,在bash/sh命令下,脚本文件可以无"执行权限",即 ...

  7. 子shell以及什么时候进入子shell

    bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html 子shell的概念贯穿整个shell,写shell脚本时更是不 ...

  8. 批量kill java进程方法-引出子shell和反引用

    方法: kill –9 `pgrep java` 使用上述命令可以将服务器上运行的所有java进程一次性kill掉. 扩展:子shell和反应用在shell脚本中的作用 先来看一个子shell的例子: ...

  9. linux 子shell subshell和函数

    关于子shell, subshell 参考:http://blog.csdn.net/sosodream/article/details/5683515 系统引导时的进程为 "原始进程&qu ...

  10. centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课

    centos  MySQL主从配置 ntsysv   chkconfig  setup命令  配置MySQL 主从 子shell  MySQL备份  kill命令  pid文件  discuz!论坛数 ...

随机推荐

  1. system调用命令行命令而不显示命令行窗口

    system调用命令行命令而不显示命令行窗口 通常用system调用命令行命令时都会弹出黑底白字的命令行窗口,下面的代码可以不显示弹出的命令行窗口. 代码如下 #pragma comment( lin ...

  2. ES6 对Number的扩展

    Number.isFinite(), Number.isNaN() ES6 在Number对象上,新提供了Number.isFinite()和Number.isNaN()两个方法. Number.is ...

  3. 关于使用response.addHeader下载中文名乱码问题

    介绍下我项目中遇到的问题:在数据库导出Excel文件的过程中,导出文件中文名始终异常,最终结果发现需要在response.addHeader 中的 filename = "xxxx" ...

  4. C#继承与多态

    继承:在程序中,如果一个类A:类B,这种机制就是继承. 子类可以继承父类的所有内容(成员)吗? 解析: 1.私有成员(属性和方法) 2.构造函数 3.final修饰过的方法,子类不能进行重写 //SE ...

  5. 随应潮流-基于ABP+Angularjs现代化应用软件开发框架(1)-总体介绍

    系列文章目录 随应潮流-基于ABP+Angulsrjs现代化应用软件开发框架(1)-总体说明 随应潮流-基于ABP+Angulsrjs现代化应用软件开发框架(2)-abp说明 随应潮流-基于ABP+A ...

  6. 【CQ18高一暑假前挑战赛5】标程

    [A:暴力] #include<bits/stdc++.h> using namespace std; ; int a[maxn],vis[maxn],N,M; int main() { ...

  7. Update 出现在的问题

    报错提示:之前的操作没有完成,运行deanup被打断,请先执行Cleanup方法. 正常右键点击Cleanup,如果只让默认值勾选,可能还是会报这个错.所以正确操作如下: 全部选中再点击OK,这样就可 ...

  8. HDMI 8193 配置

    1, User space:ProjectConfig.mkMTK_HDMI_SUPPORT = yes MTK_MULTIBRIDGE_SUPPORT = yesMTK_INTERNAL_HDMI_ ...

  9. 错误 128 无法将类型“string”隐式转换为“System.Windows.Forms.DataGridViewTextBoxColumn”

    原因是DataGridView中列的Name属性值和DataPropertyName属性值一样,比如Name="CardID",DataPropertyName="Car ...

  10. git add . 的时候遇到warning: LF will be replaced by CRLF inXXX 解决办法

    $ git add . warning: LF will be replaced by CRLF in shop/Runtime/Cache/86bbc820c9ec1 d314a9c71cf5651 ...