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