概览
每当我们在Bash shell 中运行任何命令时,默认情况下都会创建一个子 shell,并生成(分叉)一个新的子进程来执行该命令。但是,当使用 exec时,exec 后面的命令将替换当前 shell。这意味着不会创建任何子 shell,并且当前进程将替换为此新命令。
进程替换实验
-
先查看当前shell的PID
bashjagitch@jagitch-MS-7B93:tmp$ echo $$ 280513
-
打开第二个shell,查看shell 1的进程信息
bashjagitch@jagitch-MS-7B93:tmp$ ps -aef | grep 280513 jagitch 280513 22748 0 11:37 pts/0 00:00:00 bash jagitch 281157 273610 0 11:38 pts/1 00:00:00 grep --color=auto 280513
-
在shell 1中执行exec命令
bashjagitch@jagitch-MS-7B93:tmp$ exec sleep 40
-
在shell 2中再次查看shell 1的进程信息
bashjagitch@jagitch-MS-7B93:tmp$ ps -aef | grep 280513 jagitch 280513 22748 0 11:37 pts/0 00:00:00 sleep 40 jagitch 281573 273610 0 11:38 pts/1 00:00:00 grep --color=auto 280513
此时发现280513这个进程由之前的bash替换成了
sleep 40
,说明exec执行地命令不会创建子进程,而是替换掉当前进程的程序。这样可以达到节约计算机资源的目的。 -
等shell 1中地exec命令结束后,发现shell 1退出了,此时在shell 2中查看shell 1的进程ID
bashjagitch@jagitch-MS-7B93:tmp$ ps -aef | grep 280513 jagitch 281749 273610 0 11:39 pts/1 00:00:00 grep --color=auto 280513
此时发现shell 1那个进程已经被销毁了,因为默认的bash进程被exec替换为了sleep命令,这个命令执行完后就会退出,而之前那个shell进程会一直循环解释执行用户输入的命令,它不会退出被销毁。
exec的常用用法
-
脚本中进行命令替换
bashjagitch@jagitch-MS-7B93:tmp$ cat ./execdemo.sh #!/bin/bash echo first exec echo second echo last jagitch@jagitch-MS-7B93:tmp$ chmod +x ./execdemo.sh jagitch@jagitch-MS-7B93:tmp$ ./execdemo.sh first second
我们可以发现last没有被输出,因为
./execdemo.sh
在一个子进程中执行,第一个echo正常输出,但是遇到exec echo second
后,这个子进程就被替换成echo second
了,执行完这条命令该进程就退出销毁了,自然就不会执行后面的echo last
了。 -
使用exec进行日志记录
bashjagitch@jagitch-MS-7B93:tmp$ cat execlog.sh #!/bin/bash LOG_FILE="output.log" exec &> "$LOG_FILE" echo "1. script started at $(date +'%Y-%m-%d')" echo "2. find all .txt files in current dir" find -type f -name "*.txt" echo "3. make some error" cat hello echo "4. script finished at $(date +'%Y-%m-%d')" jagitch@jagitch-MS-7B93:tmp$ bash execlog.sh jagitch@jagitch-MS-7B93:tmp$ cat output.log 1. script started at 2024-06-28 2. find all .txt files in current dir ./2.txt ./1.txt ./favorite colors.txt 3. make some error cat: hello: 没有那个文件或目录 4. script finished at 2024-06-28
execlog.sh脚本中使用`exec &> "$LOG_FILE"将标准输出和标准错误都重定向到指定地文件中。
-
使用exec操作文件描述符
bashjagitch@jagitch-MS-7B93:tmp$ cat execfd.sh #!/bin/bash exec 3> fruit.txt exec 1>&3 echo "apple" echo "orange" exec 3>&- jagitch@jagitch-MS-7B93:tmp$ bash execfd.sh jagitch@jagitch-MS-7B93:tmp$ cat fruit.txt apple orange
exec 3> fruit.txt
将文件描述符重定向到fruit.txt文件exec 1>&3
把标准输出重定向到文件描述符为3的文件中exec 3>&-
的意思是关闭文件描述符
每一次点赞,都是你独特的味道。每一次关注,都是我前行的动力。感谢有你,一起成长!