21. 子shell

运行一个shell脚本会启动一个新的进程,即子shell

定义: 一个子shell是由一个shell(或shell脚本)触发的子进程

一个子shell是命令处理器(-- 在终端或者xtrem窗口给出提示符的shell)的一个独立的例子。正如你的命令在命令行提示符处被理解执行一样,一个脚本批处理一组命令。每一个shell脚本运行实际上是shell的一个支线进程(子进程)。

一个shell脚本可以自己启动多个子进程。这些子进程使得脚本进行并行处理,实际上是多个支线任务同事进行。

#!/bin/bash
# subshell-test.sh

(
# 在圆括号内,因此是一个子shell . . .
while [ 1 ]   # 无限循环.
do
  echo "Subshell running . . ."
done
)

#  脚本会永远运行,或者至少直到由Ctl-C终止。

exit $?  # 脚本结束 (但是永远无法到达这里)。



现在,运行这个脚本:
sh subshell-test.sh

另外,在脚本运行的同时, 从另一个xterm运行:
ps -ef | grep subshell-test.sh

UID       PID   PPID  C STIME TTY      TIME     CMD
500       2698  2502  0 14:26 pts/4    00:00:00 sh subshell-test.sh
500       2699  2698 21 14:26 pts/4    00:00:24 sh subshell-test.sh

          ^^^^

分析:
PID 2698, 脚本, 启动 PID 2699, 子shell.

注释: “UID ...”这一列可以通过“grep”命令筛去,但是由于说明的目的而显示在这里。

一般来说,脚本的一个外部命令会使得子进程产生分叉,[^1] 但是一个Bash内建命令不会如此。

在圆括号内的命令列

(命令1; 命令1; 命令3; ...)

子shell的变量不能被这个子shell内代码区块之外的部分看见。这些变量不能被父进程中调用,也不能被启动次子shell的shell调用。这些变量实际上是子进程局部变量

例21-1.子shell的变量范围

同样参看 $BASHPID例34-2

定义: 变量的范围是指其有意义的上下文内容,在此变量可以被引用。比如说,局部变量的范围只在函数、代码区块或子shell内的相应定义范围内,而全局变量的范围则是其出现的整个脚本区域。

内部变量 $BASH_SUBSHELL 指出一个子shell的嵌套层级时,而变量 $SHLVL 指示在子shell内不变的层级。

子shell内的路径改变不会带入到父shell中。

例21-2. 列出用户信息

一个子shell可以用来为一个命令组设定一个“特定环境”。

从这里可以看出,命令 exit 只终止正在运行的子shell,并不终止父shell或脚本。

这样的“特定环境”的一个应用是检查一个变量是否被定义。

另一个应用是检查一个锁定文件。

多个进程可以在不同子shell内并行执行。这样就可以将一个复杂的任务分解成多个子部分同时处理。

例21-3. 在子shell中运行并行进程

向子shell的I/O重定向使用管道算符"|",正如 ls -al | (命令)

在花括号间的代码块不会启动一个子shell。

{ 命令1; 命令2; 命令3; ...命令N; }

Notes

[^1] 和 exec 命令一起触发的外部命令(通常)不会分叉一个子进程 / 子shell

最后更新于

这有帮助吗?