exec 操做文件描述符实现IO重定向

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

FDm的输出复制到FDn的文件

n<&m

FDm的输入复制到FDn的文件

n>&-

关闭FDn的输出,>&-表示关闭标准输出

n<&-

关闭FDn的输入,<&-表示关闭标准输入

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 3FD 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. 同时4FD操做


 

示例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重定向与文件描述符

相关文章
相关标签/搜索