17.2.2 使用exec

exec是Shell的内建命令,执行这个命令时系统不会启动新的Shell,而是用要被执行的命令替换当前的Shell进程。因此假设在一个Shell中执行exec ls,则在列出当前目录后该Shell进程将会主动退出——如果使用ssh进行远程连接,则当前连接也会在执行完这个命令后断开。除此之外,exec还可以用于I/O重定向,表17-2总结了exec的用法。

表17-2 exec的常见用法

17.2.2 使用exec - 图1

1.将file文件中的内容作为exec的标准输入

创建文件command.txt,该文件中罗列了需要执行的命令,然后将该文件重定向为exec的标准输入,可以看到系统成功执行了文件中的所有命令。但是在命令退出后同时断开了终端,正如之前所说,系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变。所以exec并不会创建新的进程,只是替换了原来进程上下文的内容,因此当被执行的命令退出时,这个进程也随之退出了。示例如下:


  1. [root@localhost ]# cat command.txt
  2. echo "Hello"
  3. echo "World"
  4. [root@localhost ]# exec <command.txt
  5. [root@localhost ]# echo "Hello"
  6. Hello
  7. [root@localhost ]# echo "World"
  8. World
  9. [root@localhost ~]# logout

2.将file文件作为标准输出

利用exec可将标准输出全部重定向到某个文件中。下面例子中的第一条命令,即将本次会话中的所有标准输出重定向到了out01.txt文件中。你可能已注意到第二条、第三条命令均没有任何输出到屏幕,第四条命令exec>devtty是将标准输出重新定向到了显示器(devtty为显示终端)上。最后查看out01.txt文件内容,正是之前两条命令的输出内容。


  1. [root@localhost ~]# exec >out01.txt
  2. [root@localhost ]# pwd
  3. [root@localhost ]# echo "HelloWorld"
  4. [root@localhost ]# exec >devtty
  5. [root@localhost ]# cat out01.txt
  6. /root
  7. HelloWorld

3.指定文件标识符

通过exec指定文件标识符,可以通过对该标识符的操作进行文件的操作。还是拿排序为例,下面会读入fruit01.txt文件并指定标识符为3,然后对其进行排序。


  1. [root@localhost ]# cat fruit01.txt
  2. banana
  3. apple
  4. carrot
  5. [root@localhost ]# exec 3<fruit01.txt
  6. [root@localhost ~]# sort <&3
  7. apple
  8. banana
  9. carrot

实际上,文件标识符类似于很多编程语言中的“句柄”。在Linux中,文件标识符也是一种“设备”,这个标识符会出现在devfd目录中。进入这个目录,可以看到3是一个到该文件的软链接——记住:Linux下一切皆文件。


  1. [root@localhost ~]# cd devfd
  2. [root@localhost fd]# ll
  3. total 0
  4. lrwx------ 1 root root 64 May 30 03:40 0 -> devpts/1
  5. lrwx------ 1 root root 64 May 30 03:54 1 -> devpts/1
  6. lrwx------ 1 root root 64 May 30 03:54 2 -> devpts/1
  7. lrwx------ 1 root root 64 May 30 03:54 255 -> devpts/1
  8. lr-x------ 1 root root 64 May 30 03:54 3 -> rootfruit01.txt

4.关闭文件标识符

主动打开的文件标识符需要主动关闭,否则除了系统重启,该文件标识符会一直被占用。关闭文件标识符的方法如下:


  1. [root@localhost fd]# exec 3<&-
  2. [root@localhost fd]# ls -l
  3. total 0
  4. lrwx------ 1 root root 64 May 30 05:15 0 -> devpts/0
  5. lrwx------ 1 root root 64 May 30 05:39 1 -> devpts/0
  6. lrwx------ 1 root root 64 May 30 05:39 2 -> devpts/0
  7. lrwx------ 1 root root 64 May 30 05:39 255 -> devpts/0

完成后使用ls命令确认3已经消失。

5.将写入指定文件标识符的内容写入指定文件

命令及示例如下:


  1. #
  2. 创建文件标识符3
  3. ,并将写入3
  4. 的内容全部写入file
  5. 文件中
  6. [root@localhost ]# exec 3>file
  7. #
  8. 命令的输出内容写到标识符3
  9. [root@localhost ]# echo "HelloWorld" >&3
  10. [root@localhost ~]# cat file
  11. HelloWorld

6.创建文件标识符的拷贝

命令及示例如下:


  1. [root@localhost ~]# exec 3<fruit01.txt
  2. #
  3. 创建文件标识符3
  4. 的拷贝4
  5. [root@localhost ]# exec 4<&3
  6. #
  7. 可以看到3
  8. 4
  9. 都是指向同一个文件
  10. [root@localhost ]# ls -l devfd/
  11. total 0
  12. lrwx------ 1 root root 64 Oct 7 03:12 0 -> devpts/0
  13. lrwx------ 1 root root 64 Oct 7 03:12 1 -> devpts/0
  14. lrwx------ 1 root root 64 Oct 7 03:12 2 -> devpts/0
  15. lr-x------ 1 root root 64 Oct 7 03:12 3 -> rootfruit01.txt
  16. lr-x------ 1 root root 64 Oct 7 03:12 4 -> rootfruit01.txt
  17. lr-x------ 1 root root 64 Oct 7 03:12 5 -> proc2069/fd
  18. [root@localhost ~]# cat devfd/4
  19. banana
  20. apple
  21. carrot