子进程
什么是进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
查看下当前系统中的进程
1 | [root@vm-101 ~]# ps -ef |
什么是子进程
子进程就是在父进程中创建的进程。它会fork一份几乎完全一样的空间,来运行它的代码。
PID就是该程序的进程ID,PPID就是该程序的父进程ID。
父进程和子进程是两个不同的进程。进程里面的变量,函数,等不能直接访问。
什么时候会产生子进程
在bash中,主要有四中情况会产生子进程。需要特别注意,不然以后写脚本的时候,可能遇到一些奇奇怪怪的问题,无从下手。
创建一个新的bash
1
2
3
4
5
6
7
8
9
10
11[root@vm-101 ~]# echo $BASHPID # 显示当前shell的进程ID
4840
[root@vm-101 ~]# bash # 创建一个新的shell
[root@vm-101 ~]# echo $BASHPID # BASHPID和上面不一样了。
5100
[root@vm-101 ~]# ps -ef | grep bash
root 3700 3698 0 04:24 pts/1 00:00:00 -bash
root 4739 3700 0 05:25 pts/1 00:00:00 man bash
root 4840 4838 0 05:28 pts/0 00:00:00 -bash
root 5100 4840 0 05:42 pts/0 00:00:00 bash # 新创建的子shell的父进程是4840
root 5123 5100 0 05:43 pts/0 00:00:00 grep --color=auto bash管道: | |&
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84[root@vm-101 ~]# cat fork.sh
# 注释说明,好习惯
echo "当前BASHPID:$BASHPID"
let a=$BASHPID
echo "内部命令BASHPID:$BASHPID"
echo | echo "管道后面的BASHPID:$BASHPID"
echo "当前BASHPID:$BASHPID"
exit 0
[root@vm-101 ~]# bash fork.sh
当前BASHPID:5247
内部命令BASHPID:5247 # 内部命令不会创建新的进程,会在当前进程会执行。bash一共有61个内部命令
管道后面的BASHPID:5249 # 虽然是内部命令,但是用到了管道操作,所以BASHPID不一样了。
当前BASHPID:5247
########## 扩展一下内部命令
[root@vm-101 ~]# compgen -b # 全部61个bash内部命令。可以看看。了解了解
.
:
[
alias
bg
bind
break
builtin
caller
cd
command
compgen
complete
compopt
continue
declare
dirs
disown
echo
enable
eval
exec
exit
export
false
fc
fg
getopts
hash
help
history
jobs
kill
let
local
logout
mapfile
popd
printf
pushd
pwd
read
readarray
readonly
return
set
shift
shopt
source
suspend
test
times
trap
true
type
typeset
ulimit
umask
unalias
unset
wait后台: &
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16[root@vm-101 ~]# cat fork.sh
# 注释说明,好习惯
echo "当前BASHPID:$BASHPID"
echo "后台的BASHPID:$BASHPID" &
echo "当前BASHPID:$BASHPID"
exit 0
[root@vm-101 ~]# bash fork.sh
当前BASHPID:5286
当前BASHPID:5286 # 注意这个执行顺序。因为是后台创建一个新的进程,有性能开销,但是不影响前台的任务。所以这里后发先至,先打印出来了。
后台的BASHPID:5287 # 后台创建的子进程BASHPID不一样了。分组操作符:( )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17[root@vm-101 ~]# cat fork.sh
# 注释说明,好习惯
echo "当前BASHPID:$BASHPID"
( echo "分组命令的BASHPID:$BASHPID" ) # ( )是命令分组操作符
echo "当前BASHPID:$BASHPID"
exit 0
[root@vm-101 ~]# bash fork.sh
当前BASHPID:5323
分组命令的BASHPID:5324 # BASHPID也不一样了
当前BASHPID:5323调用外部命令
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[root@vm-101 ~]# cat fork.sh
# 注释说明,好习惯
echo "当前BASHPID:$BASHPID"
ping -c 5 www.baidu.com # ping不是内部命令。在5秒内,快速在另外一个终端,执行ps -ef看看新创建的子进程
echo "当前BASHPID:$BASHPID"
exit 0
[root@vm-101 ~]# bash fork.sh
当前BASHPID:5355
PING www.a.shifen.com (39.156.66.14) 56(84) bytes of data.
64 bytes from 39.156.66.14 (39.156.66.14): icmp_seq=1 ttl=63 time=6.41 ms
64 bytes from 39.156.66.14 (39.156.66.14): icmp_seq=2 ttl=63 time=7.03 ms
64 bytes from 39.156.66.14 (39.156.66.14): icmp_seq=3 ttl=63 time=6.27 ms
64 bytes from 39.156.66.14 (39.156.66.14): icmp_seq=4 ttl=63 time=7.58 ms
64 bytes from 39.156.66.14 (39.156.66.14): icmp_seq=5 ttl=63 time=7.10 ms
--- www.a.shifen.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4002ms
rtt min/avg/max/mdev = 6.270/6.882/7.583/0.482 ms
当前BASHPID:5355
[root@vm-101 ~]# ps -ef | grep ping # 另外一个终端执行的
root 5356 5355 0 06:00 pts/1 00:00:00 ping -c 5 www.baidu.com # ping进程的父进程是5355
root 5358 5100 0 06:00 pts/0 00:00:00 grep --color=auto ping命令替换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16[root@vm-101 ~]# cat fork.sh
# 注释说明,好习惯
echo "当前BASHPID:$BASHPID"
echo "命令替换时BASHPID:$(echo $BASHPID)" # 新知识点,命令替换
echo "当前BASHPID:$BASHPID"
exit 0
[root@vm-101 ~]# bash fork.sh
当前BASHPID:5407
命令替换时BASHPID:5408
当前BASHPID:5407进程替换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16[root@vm-101 ~]# cat fork.sh
# 注释说明,好习惯
echo "当前BASHPID:$BASHPID"
echo "进程替换时BASHPID: `cat <(echo $BASHPID)`"
echo "当前BASHPID:$BASHPID"
exit 0
[root@vm-101 ~]# bash fork.sh
当前BASHPID:5549
进程替换时BASHPID: 5551
当前BASHPID:5549
以上这些情况要知道比较好。shell脚本不难,这个地方可能会是一个坑,有可能会在以后遇到。遇到了,没有这些思路,很容易抓瞎。
exec
说到子进程,就改提一提exec这个命令了。
一般我们执行一个外部命令都会生成一个子进程来运行这个外部命令。但是有的时候,我们不希望这样。性能是一方面,更重要的是子进程的运行环境完全不一样了。
1 | [root@vm-101 ~]# cat fork.sh |