运行一个shell脚本时会启动另一个命令解释器. 就好像你的命令是在命令行提示下被解释的一样, 类似于批处理文件里的一系列命令.每个shell脚本有效地运行在父shell(parent shell)的一个子进程里.这个父shell是指在一个控制终端或在一个xterm窗口中给你命令指示符的进程.
shell脚本也能启动他自已的子进程. 这些子shell(即子进程)使脚本并行地,有效率地地同时运行多个子任务.
一般来说,脚本里的一个外部命令(external command)能生成(forks)出一个子进程,然而Bash内建(builtin)的命令却不这样做,因此,内建命令比起外部的等价命令执行起来更快. |
在子shell里的变量不能被这段子shell代码块之外外面的脚本访问.这些变量是不能被产生这个子shell的父进程(parent process)存取的,实际上它们是局部变量(local variables). |
例子 20-1. 子shell中的变量作用域
1 #!/bin/bash 2 # subshell.sh 3 4 echo 5 6 echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL" 7 # Bash, 版本 3, 增加了新的 $BASH_SUBSHELL 变量. 8 echo 9 10 outer_variable=Outer 11 12 ( 13 echo "Subshell level INSIDE subshell = $BASH_SUBSHELL" 14 inner_variable=Inner 15 16 echo "From subshell, \"inner_variable\" = $inner_variable" 17 echo "From subshell, \"outer\" = $outer_variable" 18 ) 19 20 echo 21 echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL" 22 echo 23 24 if [ -z "$inner_variable" ] 25 then 26 echo "inner_variable undefined in main body of shell" 27 else 28 echo "inner_variable defined in main body of shell" 29 fi 30 31 echo "From main body of shell, \"inner_variable\" = $inner_variable" 32 # $inner_variable 会以没有初始化的变量来打印 33 #+ 因为变量是在子shell里定义的"局部变量". 34 # 这个有办法补救的吗? 35 36 echo 37 38 exit 0 |
参考例子 31-2.
+
在子shell中的目录更改不会影响到父shell.
例子 20-2. 列出用户的配置文件
1 #!/bin/bash 2 # allprofs.sh: 打印所有用户的配置文件 3 4 # 由 Heiner Steven编写, 并由本书作者修改. 5 6 FILE=.bashrc # 在一般的脚本里,包含用户配置的文件是".profile". 7 # 8 9 for home in `awk -F: '{print $6}' /etc/passwd` 10 do 11 [ -d "$home" ] || continue # 如果没有家目录,跳过此次循环. 12 [ -r "$home" ] || continue # 如果目录没有读权限,跳过此次循环. 13 (cd $home; [ -e $FILE ] && less $FILE) 14 done 15 16 # 当脚本终止时,不必用'cd'命令返回原来的目录, 17 #+ 因为'cd $home'是在子shell中发生的,不影响父shell. 18 19 exit 0 |
子shell可用于为一组命令设定临时的环境变量.
1 COMMAND1 2 COMMAND2 3 COMMAND3 4 ( 5 IFS=: 6 PATH=/bin 7 unset TERMINFO 8 set -C 9 shift 5 10 COMMAND4 11 COMMAND5 12 exit 3 # 只是从子shell退出. 13 ) 14 # 父shell不受影响,变量值没有更改. 15 COMMAND6 16 COMMAND7 |
1 if (set -u; : $variable) 2> /dev/null 2 then 3 echo "Variable is set." 4 fi # 变量已经在当前脚本中被设置, 5 #+ 或是Bash的一个内部变量, 6 #+ 或是可见环境变量(指已经被导出的环境变量). 7 8 # 也可以写成 [[ ${variable-x} != x || ${variable-y} != y ]] 9 # 或 [[ ${variable-x} != x$variable ]] 10 # 或 [[ ${variable+x} = x ]] 11 # 或 [[ ${variable-x} != x ]] |
1 if (set -C; : > lock_file) 2> /dev/null 2 then 3 : # lock_file 不存在,还没有用户运行这个脚本 4 else 5 echo "Another user is already running that script." 6 exit 65 7 fi 8 9 # 由St閜hane Chazelas编程 10 #+ 由Paulo Marcel Coelho Aragao修改. |
进程在不同的子shell中可以串行地执行.这样就允许把一个复杂的任务分成几个小的子问题来同时地处理.
例子 20-3. 在子shell里进行串行处理
1 (cat list1 list2 list3 | sort | uniq > list123) & 2 (cat list4 list5 list6 | sort | uniq > list456) & 3 #列表的合并和排序同时进. 4 #放到后台运行可以确保能够串行执行. 5 # 6 #和下面的有相同的作用: 7 # cat list1 list2 list3 | sort | uniq > list123 & 8 # cat list4 list5 list6 | sort | uniq > list456 & 9 10 wait #在所有的子shell执行完成前不再执行后面的命令. 11 12 diff list123 list456 |
用"|"管道操作把I/O流重定向到子shell,例如ls -al | (command).
在一个花括号内的代码块不会运行一个子shell. { command1; command2; command3; ... } |