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

相關文章
相關標籤/搜索