1.intruductionshell
exec 用来启动一个新shell来执行指定程序,它会清除现有shell环境,而不是开启子shell来执行命令。bash
exec的另外一种做用是操做文件描述符,而此时exec不会覆盖你当前的 shell 环境 ide
2.sysopsisthis
exec 程序/命令spa
3.exec实现高级IO指针
IO的各类实现离不开对FD的操做,建立新的输入或输出文件描述符后,shell将在脚本退出时自动关闭它们,但有时也须要在脚本结束前手动关闭。xml
符号blog |
意义进程 |
n>&mci |
将FD为m的输出复制到FD为n的文件 |
n<&m |
将FD为m的输入复制到FD为n的文件 |
n>&- |
关闭FD为n的输出,>&-表示关闭标准输出 |
n<&- |
关闭FD为n的输入,<&-表示关闭标准输入 |
exec n<> filename |
以读写方式打开文件 |
IO重定向其实就是让已建立的FD指向其它的文件(修改其连接的文件),可使用ls -l /proc/$$/fd 来查看这些连接,而经过exec能够很容易的建立,复制,关闭FD,从而实现自定义的重定向操做。它对FD 0,1,2的操做也没有什么不一样,只不过鉴于三个FD在系统中默认属性决定了脚本会常常对其进行重定向操做。
用户能够直接在终端反复执行ls -l /proc/$$/fd,来观察以下exec 对FD操做的效果,来更好的理解FD和重定向的原理。当前用户也能够自行编写脚原本观察对应进程的重定向操做(ls -l /proc/PID/fd,其中PID为脚本进程PID)
[ade@h ~]$ exec 3>testout3 #建立FD3,
[ade@h ~]$ exec 4<>testout4 #exec 操做FD时,能够在一条语句中作多个操做,如上面建立的FD3,FD4,能够合并为一条语句exec 3>testout3 4<>testout4
[ade@h ~]$ ls -l /proc/$$/fd
total 0
lr-x------. 1 ade ade 64 Jan 9 20:04 0 -> /dev/pts/4
lrwx------. 1 ade ade 64 Jan 9 20:04 1 -> /dev/pts/4
lrwx------. 1 ade ade 64 Jan 9 20:04 2 -> /dev/pts/4
lrwx------. 1 ade ade 64 Jan 9 20:04 255 -> /dev/pts/4
lrwx------. 1 ade ade 64 Jan 9 20:04 3 -> /home/ade/testout3
lr-x------. 1 ade ade 64 Jan 9 20:04 4 -> /home/ade/testout4
[ade@h ~]$ echo "first line to FD3" >&3
[ade@h ~]$ cat testout
first line to FD3
[ade@h ~]$ echo "first line to FD4" >&4
[ade@h ~]$ cat testout2
first line to FD4
------------------------------------------------------------
[ade@h ~]$ exec 13>&3 14>&4 #复制FD3,FD4
[ade@h ~]$ ll /proc/$$/fd
total 0
lr-x------. 1 ade ade 64 Jan 10 10:41 0 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 1 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 13 -> /home/ade/testout3
lrwx------. 1 ade ade 64 Jan 10 10:41 14 -> /home/ade/testout4
lrwx------. 1 ade ade 64 Jan 10 10:41 2 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:42 255 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 3 -> /home/ade/testout3
lr-x------. 1 ade ade 64 Jan 10 10:41 4 -> /home/ade/testout4
[ade@h ~]$ echo "second line to FD3" >&13
[ade@h ~]$ cat testout3
first line to FD3
second line to FD3
-------------------------------------
[ade@h ~]$ exec 3>testout-rein #重定向FD3
[ade@h ~]$ ll /proc/$$/fd
total 0
lr-x------. 1 ade ade 64 Jan 10 10:41 0 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 1 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 13 -> /home/ade/testout3
lrwx------. 1 ade ade 64 Jan 10 10:41 14 -> /home/ade/testout4
lrwx------. 1 ade ade 64 Jan 10 10:41 2 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:42 255 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 3 -> /home/ade/testout-rein
lr-x------. 1 ade ade 64 Jan 10 10:41 4 -> /home/ade/testout4
[ade@h ~]$ echo "redirect line to testout-rein" >&3
[ade@h ~]$ cat testout-rein
redirect line to testout-rein
[ade@h ~]$ exec 3>&13 #重定向后恢复FD 3
[ade@h ~]$ echo "third line to FD3" >&3
[ade@h ~]$ cat testout3
first line to FD3
second line to FD3
third line to FD3
[ade@h ~]$ ll /proc/$$/fd
total 0
lr-x------. 1 ade ade 64 Jan 10 10:41 0 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 1 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 13 -> /home/ade/testout3
lrwx------. 1 ade ade 64 Jan 10 10:41 14 -> /home/ade/testout4
lrwx------. 1 ade ade 64 Jan 10 10:41 2 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:42 255 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 3 -> /home/ade/testout3
lr-x------. 1 ade ade 64 Jan 10 10:41 4 -> /home/ade/testout4
---------------------------------------------------
[ade@h ~]$ exec 3>&- 4>&- #关闭FD 3,FD 4
[ade@h ~]$ ll /proc/$$/fd
total 0
lr-x------. 1 ade ade 64 Jan 10 10:41 0 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 1 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 13 -> /home/ade/testout3
lrwx------. 1 ade ade 64 Jan 10 10:41 14 -> /home/ade/testout4
lrwx------. 1 ade ade 64 Jan 10 10:41 2 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:42 255 -> /dev/pts/0
[ade@h ~]$ exec 13>&- 14>&-
[ade@h ~]$ ll /proc/$$/fd
total 0
lr-x------. 1 ade ade 64 Jan 10 10:41 0 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 1 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:41 2 -> /dev/pts/0
lrwx------. 1 ade ade 64 Jan 10 10:42 255 -> /dev/pts/0
------------------------------------------------------------------
[ade@h ~]$ lsof -a -p $$ -d 0,1,2,3,4 #lsof查看全部打开的FD
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 10016 ade 0r CHR 136,0 0t0 3 /dev/pts/0
bash 10016 ade 1u CHR 136,0 0t0 3 /dev/pts/0
bash 10016 ade 2u CHR 136,0 0t0 3 /dev/pts/0
bash 10016 ade 3u REG 253,1 0 1050063 /home/ade/testout3
bash 10016 ade 4r REG 253,1 18 1050116 /home/ade/testout4
其它的FD操做都是一样的道理
exec 6<&0 #新建输入FD 6
exec 0<testin #重定向输入
exec 0<&6 #恢复默认输入
exec 3>&13 4>&14 13>&- 14>&- 恢复FD 3,FD 4, 关闭FD 13, FD 14. 同时4个FD操做
示例1:输入重定向与恢复
cat execin.sh
#!/bin/bash
#将FD 0复制到FD 8,用于恢复FD 0
exec 8<&0 #建立了输入文件描述符8
exec < loggg #或者exec 0< loggg 脚本中重定向输入
read a
read b
echo "------------------------"
echo $a
echo $b
echo "close FD 8:"
# 0<&8 将FD 8 复制到FD 0 ,即恢复
# 8<&- 关闭FD 8,以供其它进程使用
exec 0<&8 8<&-
echo -n " pls enter data:"
read c #标准输出恢复成键盘输入
echo $c
示例2:输出重定向与恢复
这是临时重定向脚本输出后再将输出设置为普通设置的常见方式。
cat execout.sh
#!/bin/bash
#将FD 1复制到FD 8,用于恢复FD 1
exec 8>&1 #建立了输出文件描述符8
exec > loggg #脚本中标准输出重定向
echo "output of date"
date
echo "output of df"
df
# 1>&8 将FD 8复制到FD 1,即恢复
#8>&- 关闭FD 8
exec 1>&8 8>&-
echo "------------------------"
echo "output of date"
date
echo "output of df"
df
示例3:重定向标准错误输出与恢复
cat execerr.sh
#!/bin/bash
#将FD 1复制到FD 8,FD 2复制到FD 9,以供重定向以后恢复
exec 8>&1 9>&2
#将标准输出与标准错误输出重定向到loggg文件
exec &> loggg
ls z* #有错误输出
date
#恢复FD1,FD2,关闭FD8,FD9
exec 1<&8 2>&9 8>&- 9>&-
echo "----------------"
echo "closed FD 8 and 9:"
ls z*
date
示例4:exec 建立读取/写入文件描述符
文件打开进行读写操做时,有一个指针指向操做文件的位置,读写操做时应该注意指针位置的移动,不然易形成读写混乱或都写覆盖
#!/bin/bash
exec 3<> testfile
read line <&3
echo "read: $line"
echo " this is a test line " >&3
4.参考
关于IO重定向和文件描述符的理解,请参考IO重定向与文件描述符