1. 程式人生 > >Unix shell輸入輸出重定向

Unix shell輸入輸出重定向

基於 clear 關聯 什麽 概念 定向 files 幫助 原來

敲代碼的時候,適當地打印出一些進度或者日誌信息經常能幫助我們跟蹤程序的執行結果。可是,這些結果或者日誌打印信息到屏幕上並不能作為以後檢查問題的根據。這就是重定向的作用,敲代碼的時候,我們能夠方便的將相關的打印信息到屏幕或者是從鍵盤接收輸入(這種優點就是避免直接操作文件)。利用重定向我們能夠非常方便地將輸入輸出重定向到文件或者其他地方。

1、文件描寫敘述符(以下部分來自維基百科)

文件描寫敘述符(File descriptor)是計算機科學中的一個術語。是一個用於表述指向文件的引用的抽象化概念。

文件描寫敘述符在形式上是一個非負整數。

實際上。它是一個索引值,指向內核為每個進程所維護的該進程打開文件的記錄表。當程序打開一個現有文件或者創建一個新文件時,內核向進程返回一個文件描寫敘述符。

在程序設計中,一些涉及底層的程序編寫往往會環繞著文件描寫敘述符展開。

可是文件描寫敘述符這一概念往往僅僅適用於UNIX、Linux這種操作系統。


文件描寫敘述符的優點主要有兩個:基於文件描寫敘述符的I/O操作兼容POSIX標準;在UNIX、Linux的系統調用中。大量的系統調用都是依賴於文件描寫敘述符。文件描寫敘述符的概念存在兩大缺點:在非UNIX/Linux操作系統上(如Windows NT),無法基於這一概念進行編程。由於文件描寫敘述符在形式上只是是個整數,當代碼量增大時,會使編程者難以分清哪些整數意味著數據,那些意味著文件描寫敘述符,因此,完畢的代碼可讀性也就會變得非常差,這一點一般通過消除魔術數字來解決。

對於ANSI C規範中定義的標準庫的文件I/O操作。ANSI C規範給出了一個解決方法,就是使用FILE結構體的指針。

其實。UNIX/Linux平臺上的FILE結構體的實現中往往都是封裝了文件描寫敘述符變量在當中。

2、輸入輸出重定向

2.1 stdin、stdout和stderr

簡單地說,文件描寫敘述符是與已打開文件或設備相關聯的整數,它們保持和已打開文件或設備的關聯。

最為常見的文件描寫敘述符是stdin、stdout和stderr,它們各自是0、1、2,是系統保留的文件描寫敘述符,分別相應標準輸入、標準輸出和標準錯誤。Unix系統會默認打開這三個文件描寫敘述符,並將stdin關聯到鍵盤。將stdout和stderr關聯到屏幕。這裏將的輸入輸出重定向主要就是將這三個文件描寫敘述符又一次定向到其他我們希望的文件或者設備。對於stdin。stdout和stderr重定向一般採用的操作符主要有<、>和>>,在沒有指定的詳細文件操作符的情況下,缺省是這種:command < file.txt相當於command 0< file.txt,也就是說默認是將文件重定向到文件描寫敘述符0;command > file.txt相當於command 1> file.txt也就是說默認將文件描寫敘述符1重定向到文件。>>和>同樣。假設要重定向stderr,就要顯示指定,比方command 2> file.txt,將command的錯誤信息輸出到file.txt。

2.2 重定向輸入

為了避免每次手動輸入數據,我們能夠將數據寫入一個文件,然後使用重定向將輸入重定向到該文件。這裏為了演示用的是linux的cat命令,cat命令假設不加參數,會讀取標準輸入並將其輸出到屏幕(實際上。cat用‘-’做參數也是這個效果,cat -),效果例如以下:

[lfqy@localhost ~]$ cat 
Hello, world!
Hello, world!
Ni hao!
Ni hao!
I‘m unhappy.
I‘m unhappy.//這裏按下ctrl+D相當於EOF
[lfqy@localhost ~]$ 
以下將上面的內容寫入文件test.txt。然後將cat的輸入重定向到該文件,這裏用到的是"<",這個操作符:

[lfqy@localhost ~]$ cat <test.txt 
Hello, world!
Ni hao!
I‘m unhappy.
[lfqy@localhost ~]$ 
實際上,像上面說的cat 0<test.txt效果也一樣。

當然,這裏僅僅是用cat做一個樣例。想用cat查看一個文件的內容何須這麽麻煩。

2.2 重定向輸出

2.2.1 重定向標準輸入和標準錯誤

為了測試標準錯誤,首先新建了一個test文件夾,然後在裏面創建了三個文件f1.txt、f2.txt和f.txt。

在f.txt中寫入上面的幾句話,然後將f1.txt和f2.txt的權限設置為000(chmod 000 f1.txt)。以下開始分別將標準輸出和標準錯誤重定向。

1、沒有重定向之前
[lfqy@localhost test]$ cat f*
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
Hello, world!
Ni hao!
I‘m unhappy.
2、重定向標準輸出
[lfqy@localhost test]$ cat f* > stdout.txt
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
[lfqy@localhost test]$ cat stdout.txt 
Hello, world!
Ni hao!
I‘m unhappy.
3、重定向標準輸出和標準錯誤
[lfqy@localhost test]$ cat f* 2> stderr.txt
Hello, world!
Ni hao!
I‘m unhappy.
[lfqy@localhost test]$ cat stderr.txt 
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
4、同一時候分別將標準輸出重定向到stdout.txt,將標準錯誤重定向到stderr.txt
[lfqy@localhost test]$ rm stderr.txt stdout.txt 
[lfqy@localhost test]$ cat f* 2> stderr.txt >stdout.txt
[lfqy@localhost test]$ cat stderr.txt stdout.txt 
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
Hello, world!
Ni hao!
I‘m unhappy.

假設輸出重定向的文件不存在,該文件會默認被創建。假設文件存在並有內容,當中原來的內容都會被清空。

當然,假設想要新的重定向的內容追加在原來內容的後面。可將上面的‘>‘換成‘>>‘,能夠達到效果。

2.2.2 將標準輸出和標準錯誤同一時候重定向到一個文件

這個實現起來有好幾種辦法。方法例如以下:

1、cat f* &> stdall.txt
[lfqy@localhost test]$ cat f* &> stdall.txt
[lfqy@localhost test]$ cat stdall.txt 
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
Hello, world!
Ni hao!
I‘m unhappy.
2、cat f* 1> stdall0.txt 2>&1
[lfqy@localhost test]$ cat f* 1> stdall0.txt 2>&1
[lfqy@localhost test]$ cat stdall0.txt 
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
Hello, world!
Ni hao!
I‘m unhappy.
反例:
[lfqy@localhost test]$ cat f* 2>&1 1> stdall0.txt
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
註意上面的反例。不能是cat f* 2>&1 1> stdall0.txt(由於假設先將標準錯誤重定向到標準輸出,而這時標準輸出沒有被重定向。仍然是輸出到屏幕,所以會導致將標準錯誤重定向到屏幕。),而必須是cat f* 1> stdall0.txt 2>&1(先將標準輸出重定向到文件。這時候。全部到標準輸出的內容都會被重定向到文件,因此後面重定向到標準輸出的標準錯誤也會輸出到文件。)。

上面1用的是一個略微特殊的操作符&>能夠同一時候重定向標準輸出和標準錯誤;2是將標準錯誤重定向到標準輸出,然後重定向標準輸出來達到目的。

二者的實現思路稍有不同。這裏之所以要用cat f* 1> stdall0.txt 2>&1,之所以要在1前面加一個&,是由於1作為一個系統默認創建的文件描寫敘述符。要用&來引用它。以下應該也會講到。

2.2.3 新技能get

(1) 丟棄不想要的輸出

有一個相似於垃圾桶的設備文件:/dev/null。將不想要的輸出重定向到該文件就能夠了。


1、丟棄標準輸出
[lfqy@localhost test]$ cat f* > /dev/null
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
2、丟棄標準錯誤
[lfqy@localhost test]$ cat f* 2> /dev/null
Hello, world!
Ni hao!
I‘m unhappy.
3、都丟棄(以下三種效果同樣)
[lfqy@localhost test]$ cat f* 2> /dev/null 1>/dev/null
[lfqy@localhost test]$ cat f* &> /dev/null 
[lfqy@localhost test]$ cat f* 1>/dev/null 2>&1
(2)既保存輸出到文件,又讓輸出顯示在屏幕

有時候。我們要將程序的輸出存檔,而又想看到程序的輸出(上面的重定向沒辦法看到輸出,僅僅能後來查看文件)。

這裏。用到一個命令tee,它能夠讀取標準輸入的內容,然後將其既輸出到標準輸出又寫入到文件(tee - read from standard input and write to standard output and files)。這裏要註意的是。這裏須要將命令的輸出送到管道,然後由tee來接收管道的輸入。而僅僅有標準輸出的內容能夠經過管道,所以先要將標準錯誤重定向到標準輸出。

[lfqy@localhost test]$ cat f* 2>&1 | tee tee.txt
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
Hello, world!
Ni hao!
I‘m unhappy.
[lfqy@localhost test]$ cat tee.txt 
cat: f1.txt: Permission denied
cat: f2.txt: Permission denied
Hello, world!
Ni hao!
I‘m unhappy.
這裏會自己主動創建不存在的文件。並清空已存在文件原來的內容,假設想用追加模式,請使用cat f* 2>&1 | tee -a tee.txt。


3、創建自己定義的文件描寫敘述符

0、1和2是系統保留的文件描寫敘述符。我們也能夠自己創建自己定義的文件描寫敘述符。自己定義的文件描寫敘述符主要有三種模式:僅僅讀模式。截斷模式和追加模式。

假定已經創建了文件描寫敘述符num,能夠使用&num來引用它,上文中用過&1就是這個道理。

3.1 僅僅讀模式

使用"exec num<filename"創建僅僅讀模式的文件描寫敘述符;僅僅讀方式的文件描寫敘述符僅僅能讀取一次。如需二次讀取。須要對文件描寫敘述符又一次創建。

[lfqy@localhost test]$ exec 5<f.txt
[lfqy@localhost test]$ cat <&5
Hello, world!
Ni hao!
I‘m unhappy.
[lfqy@localhost test]$ cat <&5//二次讀取的時候沒有不論什麽輸出
3.2 截斷模式

截斷模式就是指在創建該文件描寫敘述符的時候。相應文件裏原來的內容將會被清空。使用"exec num>filename"的模式創建截斷模式截斷模式的文件描寫敘述符創建之後,全部輸出到該文件描寫敘述符的內容都會依次追加在相應文件的後面,僅僅是該文件描寫敘述符創建之前的內容被清空了。

[lfqy@localhost test]$ cat f.txt 
Hello, world!
Ni hao!
I‘m unhappy.
[lfqy@localhost test]$ exec 7>f.txt
[lfqy@localhost test]$ cat f.txt 
[lfqy@localhost test]$ echo "Love" >&7
[lfqy@localhost test]$ echo "Happy" >&7
[lfqy@localhost test]$ cat f.txt 
Love
Happy
3.3 追加模式

使用"exec num>>filename"創建追加模式的文件描寫敘述符,和截斷模式不同,在創建該文件描寫敘述符的時候。相應文件裏原來的內容不會被清空,全部輸出到該文件描寫敘述符的內容都會依次追加在相應文件的後面。

[lfqy@localhost test]$ cat f.txt 
Love
Happy
[lfqy@localhost test]$ exec 8>>f.txt
[lfqy@localhost test]$ cat f.txt 
Love
Happy
[lfqy@localhost test]$ echo "Friendship" >&7
[lfqy@localhost test]$ echo "Flair" >&7
[lfqy@localhost test]$ cat f.txt 
Love
Happy
Friendship
Flair

好吧,關於文件描寫敘述符今天就到這裏了。後面學到新的內容會再補上。

Unix shell輸入輸出重定向