第二十章 子shell
每个 shell 脚本有效地运行在父 shell 的一个子进程里。这个父 shell 是指在一个控制终端或在一个 xterm 窗口中给你命令指示符的进程。
shell 脚本也能启动他自已的子进程。这些子 shell(即子进程)使脚本因为效率而同时进行多个子任务执行时能做串行处理。
一般来说,脚本里的一个外部命令(external command)能生成(forks)出一个子进程,然而 Bash 内建(builtin)的命令却不这样做,因此,内建命令比起外部的等价命令执行起来更快。
圆括号里的命令列表
(命令 1;命令 2;命令 3;...)
嵌在圆括号里的一列命令在一个子 shell 里运行。
注意: 在子 shell 里的变量不能被这段子 shell 代码块之外的脚本访问。这些变量是不能被产生这个子 shell 的父进程存取的,实际上它们是局部变量 。
Example 20-1 子shell中的变量作用域
#!/bin/bash
#
echo
echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL"
echo
outer_variable=Outer
(
echo "Subshell level INSIDE subshell = $BASH_SUBSHELL"
inner_variable=Inner
echo "From subshell, \"inner_variable\" = $inner_variable"
echo "From subshell, \"outer\" = $outer_variable"
)
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 "inner_variable defined in main body of shell"
fi
echo "From main body of shell, \"inner_variable\" = $inner_variable"
echo
exit 0
参考例子31-2
在子shell中的目录更改不会影响到父shell
Example 20-2 列出用户的配置文件
#!/bin/bash
#
FILE=.bashrc
for home in `awk -F: '{print $6}' /etc/passwd`
do
[ -d "$home" ] || continue # 如果没有家目录,跳过此次循环.
[ -r "$home" ] || continue # 如果目录没有读权限,跳过此次循环.
(cd $home; [ -e $FILE] && less $FILE)
done
exit 0
子shell可用于为一组命令设定临时的环境变量
COMMAND1
COMMAND2
COMMAND3
(
IFS=:
PATH=/bin
unset TERMINFO
set -C
shift 5
COMMAND4
COMMAND5
exit 3 # 只是从子 shell 退出。
)
# 父 shell 不受影响,变量值没有更改。
COMMAND6
COMMAND7
它的一个应用是测试是否一个变量被定义了
if (set -u; : variable) 2>/dev/null
#set -u:遇到不存在的变量就会报错
then
echo "Variable is set"
fi
#变量已经在当前脚本中被设置,或是 Bash 的一个内部变量,或是可见环境变量(指已经被导出的环境变量).
另一个应用是检查一个加锁的文件
if (set -C; : > lock_file) 2>/dev/null
#set -C:所产生的文件无法覆盖已存在的文件
then
:
else
echo "Another user is already running that script."
exit 65
fi
进程在不同的子 shell 中可以串行地执行。这样就允许把一个复杂的任务分成几个小的子问题来同时地处理。
Example 20-3 在子shell里进行串行处理
(cat list1 list2 list3 | sort | uniq > list123) &
(cat list4 list5 list6 | sort | uniq > list456) &
#列表的合并和排序同时进.
#放到后台运行可以确保能够串行执行.
##和下面的有相同的作用:
#cat list1 list2 list3 | sort | uniq > list123 &
#cat list4 list5 list6 | sort | uniq > list456 &
wait ##在所有的子 shell 执行完成前不再执行后面的命令.
diff list123 list456
用"|"管道操作把 I/O 流重定向到子 shell。例如 ls -al | (command)。
注意: 在一个花括号内的代码块不会运行一个子 shell。