原文地址: http://juke.outofmemory.cn/entry/295292java
咱們常常能在 shell 腳本中發現 >/dev/null 2>&1
這樣的語句。之前的我並無去深刻地理解這段命令的做用,照搬照用,直到上週我將這段命令不當心寫成了 2>&1>/dev/null
,出了一點小問題以後,我纔開始去了解這段命令背後的「玄機」。 linux
就像咱們平時寫的程序同樣,一段程序會處理外部的輸入,而後將運算結果輸出到指定的位置。在交互式的程序中,輸入來自用戶的鍵盤和鼠標,結果輸出到用戶的屏幕,甚至播放設備中。而對於某些後臺運行的程序,輸入可能來自於外部的一些文件,運算的結果一般又寫到其餘的文件中。並且程序在運行的過程當中,會有一些關鍵性的信息,好比異常堆棧,外部接口調用狀況等,這些都會通通寫到日誌文件裏。 shell
shell腳本也同樣,可是咱們通常在使用shell命令的時候,更多地仍是經過鍵盤輸入,而後在屏幕上查看命令的執行結果。若是某些狀況下,咱們須要將shell命令的執行結果存儲到文件中,那麼咱們就須要使用輸入輸出的重定向功能。 post
當執行shell命令時,會默認打開3個文件,每一個文件有對應的文件描述符來方便咱們使用: 測試
類型 | 文件描述符 | 默認狀況 | 對應文件句柄位置 |
---|---|---|---|
標準輸入(standard input) | 0 | 從鍵盤得到輸入 | /proc/slef/fd/0 |
標準輸出(standard output) | 1 | 輸出到屏幕(即控制檯) | /proc/slef/fd/1 |
錯誤輸出(error output) | 2 | 輸出到屏幕(即控制檯) | /proc/slef/fd/2 |
因此咱們平時在執行shell命令中,都默認是從鍵盤得到輸入,而且將結果輸出到控制檯上。可是咱們能夠經過更改文件描述符默認的指向,從而實現輸入輸出的重定向。好比咱們將1指向文件,那麼標準的輸出就會輸出到文件中。 spa
輸出重定向的使用方式很簡單,基本的一些命令以下: 日誌
命令 | 介紹 |
---|---|
command >filename | 把標準輸出重定向到新文件中 |
command 1>filename | 同上 |
command >>filename | 把標準輸出追加到文件中 |
command 1>>filename | 同上 |
command 2>filename | 把標準錯誤重定向到新文件中 |
command 2>>filename | 把標準錯誤追加到新文件中 |
咱們使用 >
或者 >>
對輸出進行重定向。符號的左邊表示文件描述符, 若是沒有的話表示1,也就是標準輸出
,符號的右邊能夠是一個文件,也能夠是一個輸出設備。當使用 >
時,會判斷右邊的文件存不存在,若是存在的話就先 刪除 ,而後建立一個新的文件,不存在的話則直接建立。可是當使用 >>
進行追加時,則不會刪除原來已經存在的文件。 code
爲了更好地理解輸出重定向,感覺重定向的「魅力」,咱們看一下如下的例子:咱們建立一個 測試 目錄 ,目錄下面僅有一個a.txt文件。 接口
# tree.└── a.txt directories,1 file # ls a.txt b.txt ls:沒法訪問b.txt:沒有那個文件或目錄 a.txt
在咱們執行 ls a.txt b.txt
以後,一共有兩種輸出,其中 ls:沒法訪問b.txt:沒有那個文件或目錄
是錯誤輸出, a.txt
是標準輸出。 get
# ls a.txt b.txt 1>out ls:沒法訪問b.txt:沒有那個文件或目錄# cat out a.txt # ls a.txt b.txt >>out ls:沒法訪問b.txt:沒有那個文件或目錄# cat out a.txt a.txt
在上述命令中,咱們將原來的標準輸出重定向到了out文件中,因此控制檯只剩下了錯誤提示。而且當執行了追加操做時,out文件的內容非但沒有被清空,反而又多了一條 a.txt
。
同理,咱們也能夠將錯誤輸出重定向到文件中:
# ls a.txt b.txt 2>err a.txt # cat err ls:沒法訪問b.txt:沒有那個文件或目錄# ls a.txt b.txt >out 2>err# cat out a.txt # cat err ls:沒法訪問b.txt:沒有那個文件或目錄
看到這裏, 朋友們 可能會發現 >out2>err
和咱們在一開頭提到的 >/dev/null2>&1
已經很像了,別急,這待會再說。
在理解了輸出重定向以後,理解輸入重定向就會容易得多。對輸入重定向的基本命令以下:
命令 | 介紹 |
---|---|
command <filename | 以filename文件做爲標準輸入 |
command 0<filename | 同上 |
command <<delimiter | 從標準輸入中讀入,直到遇到delimiter分隔符 |
咱們使用 <
對輸入作重定向, 若是符號左邊沒有寫值,那麼默認就是0
。
咱們此次以cat命令爲例,若是cat後面沒有跟文件名的話,那它的做用就是將標準輸入(好比鍵盤)回顯到標準輸出(好比屏幕)上:
# cat test test
咱們能夠將利用輸入重定向,將咱們在鍵盤上敲入的字符寫入到文件中。咱們須要使用ctrl+c來結束輸入:
# cat >out test ^C # cat out test
好了,此時咱們以爲本身在鍵盤上敲比較累,仍是直接讓cat讀取一個文件吧。那麼咱們須要利用輸入重定向:
# cat input aaa # cat >out <input# cat out aaa
神奇的事情發生了,out文件裏面的內容被替換成了input文件裏的內容。那麼 <<
又是什麼做用呢?咱們再看:
# cat >out <<end>123> test >end# cat out test
咱們看到,當咱們輸入完 cat >out<<end
,而後敲下回車以後,命令並無結束,此時cat命令像一開始同樣,等待你給它輸入 數據 。而後當咱們敲入 end
以後,cat命令就結束了。 end
以前輸入的字符都已經被寫入到了out文件中。這就是輸入分割符的做用。
好了,在有了以上知識的基礎上,咱們再來看開頭提到的 >/dev/null2>&1
。這條命令其實分爲兩命令,一個是 >/dev/null
,另外一個是 2>&1
。
這條命令的做用是將標準輸出1重定向到/dev/null中。/dev/null表明 linux 的空設備文件,全部往這個文件裏面寫入的內容都會丟失,俗稱「黑洞」。那麼執行了 >/dev/null
以後,標準輸出就會再也不存在,沒有任何地方可以找到輸出的內容。
這條命令用到了重定向綁定,採用&能夠將兩個輸出綁定在一塊兒。這條命令的做用是錯誤輸出將和標準輸出同用一個文件描述符,說人話就是錯誤輸出將會和標準輸出輸出到同一個地方。
linux在執行shell命令以前,就會肯定好全部的輸入輸出位置,而且從左到右依次執行重定向的命令,因此 >/dev/null2>&1
的做用就是讓標準輸出重定向到/dev/null中(丟棄標準輸出),而後錯誤輸出因爲重用了標準輸出的描述符,因此錯誤輸出也被定向到了/dev/null中,錯誤輸出一樣也被丟棄了。執行了這條命令以後, 該條shell命令將不會輸出任何信息到控制檯,也不會有任何信息輸出到文件中 。
【插入一段本身的筆記】在Linux上試驗,兩個順序不一致的確會像下文講的同樣。可是在使用java命令 java MyProgramm 2>&1 >/path/to/1.txt 時,並無不同,這種寫法也是標準錯誤和標準輸出都重定向到了1.txt文件中。應該是java命令作了某些改動。
再回到 文章 的開頭,我說我弄反了 >/dev/null
和 2>&1
拼裝的順序,致使出了一點小問題。乍眼看這兩條命令貌似是等同的,但其實大爲不一樣。剛纔提到了,linux在執行shell命令以前,就會肯定好全部的輸入輸出位置,而且從左到右依次執行重定向的命令。那麼咱們一樣從左到右地來分析 2>&1>/dev/null
:
咱們用一個表格來更好地說明這兩條命令的區別:
命令 | 標準輸出 | 錯誤輸出 |
---|---|---|
>/dev/null 2>&1 | 丟棄 | 丟棄 |
2>&1 >/dev/null | 丟棄 | 屏幕 |
那麼可能會有些同窗會疑問,爲何要用重定向綁定,而不是像 >/dev/null2>/dev/null
這樣子重複一遍呢。
爲了回答這個問題,咱們回到剛纔介紹輸出重定向的場景。咱們嘗試將標準輸出和錯誤輸出都定向到out文件中:
# ls a.txt b.txt >out 2>out# cat out a.txt �法訪問b.txt:沒有那個文件或目錄
WTF?居然出現了亂碼,這是爲啥呢?這是由於採用這種寫法,標準輸出和錯誤輸出會搶佔往out文件的管道,因此可能會致使輸出內容的時候出現缺失、覆蓋等狀況。如今是出現了亂碼,有時候也有可能出現只有error信息或者只有正常信息的狀況。無論怎麼說,採用這種寫法,最後的狀況是沒法預估的。
並且,因爲out文件被打開了兩次,兩個文件描述符會搶佔性的往文件中輸出內容,因此總體 IO 效率不如 >/dev/null2>&1
來得高。
咱們常用 nohup command &
命令形式來啓動一些後臺程序,好比一些 java 服務:
# nohup java -jar xxxx.jar &
爲了避免讓一些執行信息輸出到前臺(控制檯),咱們還會加上剛纔提到的 >/dev/null2>&1
命令來丟棄全部的輸出:
# nohup java -jar xxxx.jar >/dev/null 2>&1 &
本文主要介紹了linux重定向的原理以及一些基本命令,而且詳細地分析了 >/dev/null2>&1
這個命令以及一些注意點。
總而言之,在工做中用到最多的就是 nohup command >/dev/null2>&1&
命令, 但願 你們可以好好掌握。
接着本文的場景,下面命令,錯誤輸出會輸出到什麼地方呢?
# ls a.txt b.txt 2>&1 >/dev/null 2>&1// 答案: 注意上面一句話,Linux在執行shell命令以前就已經肯定了輸入輸出的位置,而且從左往右依次執行重定向的命令。在執行以前,這個命令從左往右: 標準錯誤 綁定至標準輸出上(即屏幕), 而後標準輸出重定向到/dev/null,而後標準錯誤又從新綁定到標準輸出(如今是/dev/null了),因此最終,標準錯誤和標準輸出都重定向到了空設備/dev/null上了。