首页 > 代码库 > exec 操作文件描述符实现IO重定向
exec 操作文件描述符实现IO重定向
1.intruduction
exec 用来启动一个新shell来执行指定程序,它会清除现有shell环境,而不是开启子shell来执行命令。
exec的另一种作用是操作文件描述符,而此时exec不会覆盖你当前的 shell 环境
2.sysopsis
exec 程序/命令
3.exec实现高级IO
IO的各种实现离不开对FD的操作,创建新的输入或输出文件描述符后,shell将在脚本退出时自动关闭它们,但有时也需要在脚本结束前手动关闭。
符号 | 意义 |
n>&m | 将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重定向与文件描述符
本文出自 “Adelphos” 博客,请务必保留此出处http://adelphos.blog.51cto.com/2363901/1601563
exec 操作文件描述符实现IO重定向