shell中的輸出重定向


shell中默認有三個標准設備:標准輸入(STDIN)、標准輸出(STDOUT)、標准錯誤(STDERR)。

Linux系統中,一切(或幾乎一切)都是文件。因此,標准輸入的文件描述符是0,標准輸出的文件描述符是1,標准錯誤的文件描述符是2。

shell命令的輸出默認顯示在終端顯示器上,示例如下:

$ echo hello world
hello world

可以使用輸出重定向符號把標准輸出重定向到一個文件,示例如下:

$ echo hello world > log.txt
$ cat log.txt
hello world

標准輸出的文件描述符為1,該值為輸出重定向符號的默認值,可以省略。因此,上面的示例等效為:

$ echo hello world 1> log.txt  (這里的 1 與 > 符號之間不能有空格)
$ cat log.txt
hello world

當然我們也可以使用輸出重定向符號對標准錯誤進行重定向,但必須在 > 符號前明確指定標准錯誤的文件描述符,即使用 2> 對標准錯誤進行重定向。

 

既然提到了輸出重定向,就必須說明輸出重定向符號有兩種:> 符號 和 >> 符號。區別如下:

  • > file:打開file文件時會先清空文件,然后添加輸出信息。
  • >> file:打開file文件時不清空文件,直接在file文件結尾處添加輸出信息。

示例如下:

$ cat log.txt
hello world
$ >> log.txt
$ cat log.txt
hello world
$ > log.txt
$ cat log.txt
$

如果願意,可以將STDOUT和STDERR輸出重定向到同一個輸出文件。為此,bash shell提供了一個特殊的重定向符號,即 &> 符號。

使用 &> 符號,命令生成的所有輸出都發送到同一位置,包括數據和錯誤。而且bash shell自動使錯誤信息的優先級高於標准輸出,這樣你就可以一起查看錯誤信息,而不用在整個輸出文件中查找。貌似對cat命令的輸出不起作用。

 

重定向到某個文件描述符

重定向到某個文件描述符時,必須在文件描述符前面添加 & 符號。必須這樣的原因:因為我們知道類似1,2這樣的文件描述符也是標准的Linux文件名稱,添加 & 符號以做區分。

這樣一來,我們經常在腳本中見到的 2>&1 命令是不是很好理解了?是的,就是把標准錯誤重定向到標准輸出。這不是廢話嘛,標准錯誤默認就跟標准輸出在同一個位置━━終端顯示器。對的,使用終端顯示器作為輸出設備時是這樣的,如果我們要把輸出重定向一個文件中時,我們就要使用 2>&1 命令了。說到這里,問題來了,如下:

command > file 2> file 與 command > file 2>&1 效果一樣嗎?

效果貌似一樣:因為不管是command產生的標准輸出信息還是標准錯誤信息都重定向到了file文件里。確實如此,但也有讓人意料之外的地方:

command > file 2> file 命令把STDOUT和STDERR都直接送到file文件中,file文件會被打開兩次,這樣STDOUT和STDERR會相互覆蓋。該命令執行時相當於兩個進程同時向同一個文件中寫數據,你寫你的,我寫我的,也不進行同步,寫完拉倒。打開文件一看,數據重疊,亂七八糟。示例如下:

$ cat badfile log.txt > log 2> log
$ cat log
hello world
: No such file or directory
$

command > file 2>&1 命令把STDOUT直接送往file文件,而STDERR經由STDOUT的通道把數據信息送到file文件中。此時,file文件只被打開了一次,因此標准輸出數據和標准錯誤數據不會相互覆蓋,而是井然有序。示例如下:

$ cat badfile log.txt > log 2>&1
$ cat log
cat: badfile: No such file or directory
hello world
$

I/O效率上來說,command > file 2> file 相比於 command > file 2>&1 要低,而且會出現數據相互覆蓋的情況。因此,我們一般會使用后面這條命令。

 

在同一個命令中多次進行輸出重定向

如果我們在同一個命令中進行了多次輸出重定向操作,會出現什么情況呢?最終命令的輸出會重定向到最后一次重定向的位置。讀起來很拗口,但實際操作一下就明白了。

 

$ ls (空目錄)
$ tty (查看終端顯示器名稱)
/dev/pts/7
$ echo hello world > log.txt 1>/dev/pts/7 2>&1
hello world
$ ls
log.txt
$ cat log.txt
$

 

echo hello world > log.txt 1>/dev/pts/7 2>&1 命令首先把標准輸出重定向到log.txt文件,由於當前目錄下並不存在該文件,因此會創建該文件,並把文件清空;接着命令又把標准輸出重定向到了終端顯示器;最后又把標准錯誤重定向到了標准輸出。因此命令的輸出還是被發送到了終端顯示器上,命令結束,文件關閉,結果log.txt文件里什么數據都沒有寫入,只是創建了一個空白的文件。

 

最后說明

最后要說明的是,使用 > 符號進行重定向時,shell並不總是輕松瀟灑地清空重定向文件,比如/proc目錄下的文件,shell一般會檢查要寫入的數據,如果要寫入的數據或者寫入的方式有問題,shell可能會提醒你,也可能不提醒你。

有提示的示例如下:

root@lj:~# cat /proc/sys/net/ipv6/route/max_size
4096
root@lj:~# echo hello > /proc/sys/net/ipv6/route/max_size
-bash: echo: write error: Invalid argument
root@lj:~# cat /proc/sys/net/ipv6/route/max_size
4096
root@lj:~#

沒有提示的示例如下:

# cat /proc/sys/net/netfilter/nf_conntrack_udp_timeout
180
# echo hello > /proc/sys/net/netfilter/nf_conntrack_udp_timeout
# cat /proc/sys/net/netfilter/nf_conntrack_udp_timeout
180
#

因此,即便有時候某條命令執行完成后沒有任何提示信息,貌似成功了,我們還是應該檢查一下相關數據或文件,看看是否真的執行成功了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM