exec <filename命令會將stdin重定向到文件中. 從這句開始, 全部的stdin就都來自於這個文件了, 而不是標準輸入(一般都是鍵盤輸入). 這樣就提供了一種按行讀取文件的方法, 而且可使用sed和/或awk來對每一行進行分析.shell
使用exec重定向stdinbash
1 #!/bin/bash 2 # 使用'exec'重定向stdin. 3 4 5 exec 6<&0 # 將文件描述符#6與stdin連接起來. 6 # 保存stdin. 7 8 exec < data-file # stdin被文件"data-file"所代替. 9 10 read a1 # 讀取文件"data-file"的第一行. 11 read a2 # 讀取文件"data-file"的第二行. 12 13 echo 14 echo "Following lines read from file." 15 echo "-------------------------------" 16 echo $a1 17 echo $a2 18 19 echo; echo; echo 20 21 exec 0<&6 6<&-22 # 如今將stdin從fd #6中恢復, 由於剛纔咱們把stdin重定向到#6了, 23 #+ 而後關閉fd #6 ( 6<&- ), 好讓這個描述符繼續被其餘進程所使用. 24 # 25 # <&6 6<&- 這麼作也能夠. 26 27 echo -n "Enter data " 28 read b1 # 如今"read"已經恢復正常了, 就是可以正常的從stdin中讀取. 29 echo "Input read from stdin." 30 echo "----------------------" 31 echo "b1 = $b1" 32 33 echo 34 35 exit 0
一樣的, exec >filename命令將會把stdout重定向到一個指定的文件中. 這樣全部命令的輸出就都會發送到那個指定的文件, 而不是stdout.spa
exec N > filename會影響整個腳本或當前shell. 對於這個指定PID的腳本或shell來講,從這句命令執行以後, 就會重定向到這個文件中, 然而 . . .N > filename只會影響新fork出來的進程, 而不會影響整個腳本或shell. rest
使用exec來重定向stdoutcode
1 #!/bin/bash 2 # reassign-stdout.sh 3 4 LOGFILE=logfile.txt 5 6 exec 6>&1 # 將fd #6與stdout連接起來. 7 # 保存stdout. 8 9 exec > $LOGFILE # stdout就被文件"logfile.txt"所代替了. 10 11 # ----------------------------------------------------------- # 12 # 在這塊中全部命令的輸出都會發送到文件$LOGFILE中. 13 14 echo -n "Logfile: " 15 date 16 echo "-------------------------------------" 17 echo 18 19 echo "Output of \"ls -al\" command" 20 echo 21 ls -al 22 echo; echo 23 echo "Output of \"df\" command" 24 echo 25 df 26 27 # ----------------------------------------------------------- # 28 29 exec 1>&6 6>&- # 恢復stdout, 而後關閉文件描述符#6. 30 31 echo 32 echo "== stdout now restored to default == " 33 echo 34 ls -al 35 echo 36 37 exit 0
使用exec在同一個腳本中重定向stdin和stdoutblog
1 #!/bin/bash 2 # upperconv.sh 3 # 將一個指定的輸入文件轉換爲大寫. 4 5 E_FILE_ACCESS=70 6 E_WRONG_ARGS=71 7 8 if [ ! -r "$1" ] # 判斷指定的輸入文件是否可讀? 9 then 10 echo "Can't read from input file!" 11 echo "Usage: $0 input-file output-file" 12 exit $E_FILE_ACCESS 13 fi # 即便輸入文件($1)沒被指定 14 #+ 也仍是會以相同的錯誤退出(爲何?). 15 16 if [ -z "$2" ] 17 then 18 echo "Need to specify output file." 19 echo "Usage: $0 input-file output-file" 20 exit $E_WRONG_ARGS 21 fi 22 23 24 exec 4<&0 25 exec < $1 # 將會從輸入文件中讀取. 26 27 exec 7>&1 28 exec > $2 # 將寫到輸出文件中. 29 # 假設輸出文件是可寫的(添加檢查?). 30 31 # -----------------------------------------------32 cat - | tr a-z A-Z # 轉換爲大寫. 33 # ^^^^^ # 從stdin中讀取. 34 # ^^^^^^^^^^ # 寫到stdout上. 35 # 然而, stdin和stdout都被重定向了. 36 # -----------------------------------------------37 38 exec 1>&7 7>&- # 恢復stout. 39 exec 0<&4 4<&- # 恢復stdin. 40 41 # 恢復以後, 下邊這行代碼將會如預期的同樣打印到stdout上. 42 echo "File \"$1\" written to \"$2\" as uppercase conversion." 43 44 exit 0
I/O重定向是一種避免可怕的子shell中不可訪問變量問題的方法.進程
避免子shellci
1 #!/bin/bash 2 # avoid-subshell.sh 3 # 由Matthew Walker所提出的建議. 4 5 Lines=0 6 7 echo 8 9 cat myfile.txt | while read line; # (譯者注: 管道會產生子shell) 10 do { 11 echo $line 12 (( Lines++ )); # 增長這個變量的值 13 #+ 可是外部循環卻不能訪問. 14 # 子shell問題. 15 } 16 done 17 18 echo "Number of lines read = $Lines" # 0 19 # 錯誤! 20 21 echo "------------------------" 22 23 24 exec 3<> myfile.txt 25 while read line <&3 26 do { 27 echo "$line" 28 (( Lines++ )); # 增長這個變量的值 29 #+ 如今外部循環就能夠訪問了. 30 # 沒有子shell, 如今就沒問題了. 31 } 32 done 33 exec 3>&-34 35 echo "Number of lines read = $Lines" # 8 36 37 echo 38 39 exit 0