17.2.2 使用exec
exec是Shell的内建命令,执行这个命令时系统不会启动新的Shell,而是用要被执行的命令替换当前的Shell进程。因此假设在一个Shell中执行exec ls,则在列出当前目录后该Shell进程将会主动退出——如果使用ssh进行远程连接,则当前连接也会在执行完这个命令后断开。除此之外,exec还可以用于I/O重定向,表17-2总结了exec的用法。
表17-2 exec的常见用法
1.将file文件中的内容作为exec的标准输入
创建文件command.txt,该文件中罗列了需要执行的命令,然后将该文件重定向为exec的标准输入,可以看到系统成功执行了文件中的所有命令。但是在命令退出后同时断开了终端,正如之前所说,系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变。所以exec并不会创建新的进程,只是替换了原来进程上下文的内容,因此当被执行的命令退出时,这个进程也随之退出了。示例如下:
- [root@localhost ]# cat command.txt
- echo "Hello"
- echo "World"
- [root@localhost ]# exec <command.txt
- [root@localhost ]# echo "Hello"
- Hello
- [root@localhost ]# echo "World"
- World
- [root@localhost ~]# logout
2.将file文件作为标准输出
利用exec可将标准输出全部重定向到某个文件中。下面例子中的第一条命令,即将本次会话中的所有标准输出重定向到了out01.txt文件中。你可能已注意到第二条、第三条命令均没有任何输出到屏幕,第四条命令exec>devtty是将标准输出重新定向到了显示器(devtty为显示终端)上。最后查看out01.txt文件内容,正是之前两条命令的输出内容。
- [root@localhost ~]# exec >out01.txt
- [root@localhost ]# pwd
- [root@localhost ]# echo "HelloWorld"
- [root@localhost ]# exec >devtty
- [root@localhost ]# cat out01.txt
- /root
- HelloWorld
3.指定文件标识符
通过exec指定文件标识符,可以通过对该标识符的操作进行文件的操作。还是拿排序为例,下面会读入fruit01.txt文件并指定标识符为3,然后对其进行排序。
- [root@localhost ]# cat fruit01.txt
- banana
- apple
- carrot
- [root@localhost ]# exec 3<fruit01.txt
- [root@localhost ~]# sort <&3
- apple
- banana
- carrot
实际上,文件标识符类似于很多编程语言中的“句柄”。在Linux中,文件标识符也是一种“设备”,这个标识符会出现在devfd目录中。进入这个目录,可以看到3是一个到该文件的软链接——记住:Linux下一切皆文件。
- [root@localhost ~]# cd devfd
- [root@localhost fd]# ll
- total 0
- lrwx------ 1 root root 64 May 30 03:40 0 -> devpts/1
- lrwx------ 1 root root 64 May 30 03:54 1 -> devpts/1
- lrwx------ 1 root root 64 May 30 03:54 2 -> devpts/1
- lrwx------ 1 root root 64 May 30 03:54 255 -> devpts/1
- lr-x------ 1 root root 64 May 30 03:54 3 -> rootfruit01.txt
4.关闭文件标识符
主动打开的文件标识符需要主动关闭,否则除了系统重启,该文件标识符会一直被占用。关闭文件标识符的方法如下:
- [root@localhost fd]# exec 3<&-
- [root@localhost fd]# ls -l
- total 0
- lrwx------ 1 root root 64 May 30 05:15 0 -> devpts/0
- lrwx------ 1 root root 64 May 30 05:39 1 -> devpts/0
- lrwx------ 1 root root 64 May 30 05:39 2 -> devpts/0
- lrwx------ 1 root root 64 May 30 05:39 255 -> devpts/0
完成后使用ls命令确认3已经消失。
5.将写入指定文件标识符的内容写入指定文件
命令及示例如下:
- #
- 创建文件标识符3
- ,并将写入3
- 的内容全部写入file
- 文件中
- [root@localhost ]# exec 3>file
- #
- 命令的输出内容写到标识符3
- 中
- [root@localhost ]# echo "HelloWorld" >&3
- [root@localhost ~]# cat file
- HelloWorld
6.创建文件标识符的拷贝
命令及示例如下:
- [root@localhost ~]# exec 3<fruit01.txt
- #
- 创建文件标识符3
- 的拷贝4
- [root@localhost ]# exec 4<&3
- #
- 可以看到3
- 和4
- 都是指向同一个文件
- [root@localhost ]# ls -l devfd/
- total 0
- lrwx------ 1 root root 64 Oct 7 03:12 0 -> devpts/0
- lrwx------ 1 root root 64 Oct 7 03:12 1 -> devpts/0
- lrwx------ 1 root root 64 Oct 7 03:12 2 -> devpts/0
- lr-x------ 1 root root 64 Oct 7 03:12 3 -> rootfruit01.txt
- lr-x------ 1 root root 64 Oct 7 03:12 4 -> rootfruit01.txt
- lr-x------ 1 root root 64 Oct 7 03:12 5 -> proc2069/fd
- [root@localhost ~]# cat devfd/4
- banana
- apple
- carrot