shell輸出的那個垃圾桶——/dev/null

昨晚花費一整晚在知乎回答了一個關於shell裏面的重定向輸出到/dev/null的問題。果斷今晚也同步發在這裏,反正也沒人看~~~~



以下來自一個重度linux使用患者不請自來的回答。

先用簡單的語言回答題主的問題:

shell程序中 2> /dev/null 代表什麼意思?

答:“2> /dev/null” 代表忽略掉錯誤提示信息。

如題 2> 代表什麼意思?講錯誤輸出刪除?

答:“2>” 代表重定向操作錯誤提示信息。只有這兩個字符並不能刪除錯誤輸出。

如果有正確的輸出並賦值給i,i會得到正確的值嗎?

答:i會得到正確的值。

上面的三個回答是我認爲相對比較友好,容易理解的回答。


---------------------------------------我是囉哩囉唆回答的分割線-------------------------------------


  下面,咱們一起來看看這個命令操作涉及到的知識點(敲黑板。。。。)題主問題裏描述的這條命令其實涉及到三部分的內容,如下圖:

<img src="https://pic1.zhimg.com/v2-32b909c43d75fa9c1f7c9286fdbffdc4_b.png" data-rawwidth="247" data-rawheight="175" class="content_image" width="247">v2-32b909c43d75fa9c1f7c9286fdbffdc4_b.pn(原諒我奇怪的畫風……)
  下面的所有回到都是假設大家對linux沒有太多的瞭解所作的,如有高手,打臉的時候請輕一點。+_+


1. 文件描述符
  下面手打一段《linux shell腳本攻略》的描述(如有侵權我會刪除的 T_T):

文件描述符是與文件輸入、輸出關聯的整數。它們用來跟蹤已打開的文件。最常見的文件描述符是stidin、stdout、和stderr。我們可以將某個文件描述符的內容重定向到另外一個文件描述符中。
                                                                                       《linux shell腳本攻略》


文件描述符我們常見的就是系統預留的0,1和2這三個,他們的意義分別有如下對應關係:

  • 0 —— stdin(標準輸入)

  • 1 —— stdout (標準輸出)

  • 2 —— stderr (標準錯誤)


  其中,shell編程裏經常用到的就是描述符1,和描述符2。這樣下面我們來舉兩個栗子,就知道神馬是1和2了:
1 —— stdout
  假設:在當前目錄下我們“有且只有”一個文件名爲 123.txt 的文本文件。這個時候我們運行下面的命令【ls 123.txt】:

<img src="https://pic4.zhimg.com/v2-8830db673e8054c3050bc47f3d083c73_b.png" data-rawwidth="622" data-rawheight="158" class="origin_image zh-lightbox-thumb" width="622" data-original="https://pic4.zhimg.com/v2-8830db673e8054c3050bc47f3d083c73_r.png">我們就會獲得一個v2-8830db673e8054c3050bc47f3d083c73_b.pn  我們就會獲得一個標準輸出stdout的輸出結果“123.txt” 。
2 —— stdout
  按照上面同樣的假設,我們運行另外一跳命令【ls abc.txt】:
<img src="https://pic1.zhimg.com/v2-32eebce74f8dbe4f8ea6c1a3cee4684c_b.png" data-rawwidth="608" data-rawheight="112" class="origin_image zh-lightbox-thumb" width="608" data-original="https://pic1.zhimg.com/v2-32eebce74f8dbe4f8ea6c1a3cee4684c_r.png">我們就會獲得一個v2-32eebce74f8dbe4f8ea6c1a3cee4684c_b.pn  我們就會獲得一個標準錯誤stderr的輸出結果“ls:無法訪問abc.txt:沒有那個文件或目錄”
有同學應該會覺得,這兩個事例好像跟1和2這兩個阿拉伯數字好像沒有關係。這個就要結合第二個知識點“重定向操作”來理解了。
2.重定向操作
  書裏找不到準確的關於重定向的描述,我很不要臉滴來說一下我的理解吧。重定向操作,其實就是通過在shell命令後面追加一個重定向操作符號,將shell命令對應的文件描述符輸出的文本信息重新輸入到另外一個指定文件的操作。
  重定向操作符號有兩個>和>>。儘管這兩個操作符都可以將重定向到文件,但是前者會先清空文件,再寫入內容;後者會將內容追加到現有文件的尾部。(對了,重定向的操作制定的文件如果原來不存在的話,重定向的操作會主動創建這個文件名的文件的)
  下面我們結合第1個知識點文件描述符來舉栗子吧。
重定向標準輸出stdout
<img src="https://pic2.zhimg.com/v2-344ea7a024ecd442d39ab9f6e68ff0ad_b.png" data-rawwidth="557" data-rawheight="136" class="origin_image zh-lightbox-thumb" width="557" data-original="https://pic2.zhimg.com/v2-344ea7a024ecd442d39ab9f6e68ff0ad_r.png">如上圖所示,對比沒有添加重定向的操作,ls命令在使用之後並沒有將字符“123.txt”這個字符串打印到屏幕上。在緊接着的cat操作之後,我們可以看到本來應該輸出字符串被記錄在了stdout.txt這個文件裏面了。v2-344ea7a024ecd442d39ab9f6e68ff0ad_b.pn  如上圖所示,對比沒有添加重定向的操作,ls命令在使用之後並沒有將字符“123.txt”這個字符串打印到屏幕上。在緊接着的cat操作之後,我們可以看到本來應該輸出字符串被記錄在了stdout.txt這個文件裏面了。
  其實,對於標準輸出的重定向操作,>等同於1>。上面栗子執行命令【ls 123.txt > stdout.txt】得到的效果也是一樣的。
重定向標準錯誤stderr
<img src="https://pic3.zhimg.com/v2-cf091eefd7ca4eca5dc44dc8ba5bf8ee_b.png" data-rawwidth="545" data-rawheight="134" class="origin_image zh-lightbox-thumb" width="545" data-original="https://pic3.zhimg.com/v2-cf091eefd7ca4eca5dc44dc8ba5bf8ee_r.png">如上圖所示,文件描述符2,標準錯誤的重定向也是同樣的原理被記錄在了文件stderr.txt這個文件裏面了。v2-cf091eefd7ca4eca5dc44dc8ba5bf8ee_b.pn  如上圖所示,文件描述符2,標準錯誤的重定向也是同樣的原理被記錄在了文件stderr.txt這個文件裏面了。


描述符的重定向還有下面的幾種用法:
你可以將stderr單獨定向到一個文件,將stdout重定向到另一個文件:

cmd 2>stderr.txt 1>stdout.txt

也可以利用下面的方法,將stderr轉換成stdout,使得stderr和stdout都被重新丁香到同一個文件中:

cmd> output.txt 2>&1

或者採用這個方法(這個經常用到,我個人比較喜歡用這個,少寫幾個字符(*^__^*) )

cmd &> output.txt

(終於最後一個知識點,原來認真答題碼字這麼嘞。摔~)
3. linux特殊文件
手抄一段《linux shell腳本攻略》描述:

/dev/null是一個特殊的設備文件,這個文件接收到的任何數據都會被丟棄。因此,null這個設備通常也被成爲位桶(bit bucket)或黑洞。

  簡單地理解就是,重定向操作給這個/dev/null文件的所有東西都會被丟棄。
  因爲這些文件描述符輸出的字符串,總是會顯示出來的。如果我們在shell編程的時候,操作到某一條命令的返回結果,我們不想要這個時候又不想讓這個輸出結果打印到屏幕上(打印錯誤,多不好看對不對^_^)我們就可以重定向到/dev/null這個文件來,由/dev/null這個文件負責處理後事。
  這個丟棄的結果又不能粗暴的認爲是刪除錯誤輸出,這個操作是一個丟棄重定向輸入輸出的操作。形象地理解就是,ATM機打印的紙質流水賬單(stdout和stderr)本來應該你來保存處理的,但是你又沒有用放在手裏(打印屏幕)又礙事,所以賬單從你的手裏重新被丟到了垃圾桶(/dev/null)了。但是,垃圾桶的垃圾是怎麼處理的你是不知道的。
  不知道上面的描述,答主是不是能明白這三個知識點了?
  只要理解了上面的三個點,其實答主的第三個問題很好滴能解決了。

問題3的思路
讓一個變量獲得命令輸出的結果,是下面這樣的處理:

i=$(ls 123.txt)

這樣,i 就能獲得命令【ls 123.txt】輸出在屏幕的所有結果了。無論輸出的是stdout輸出還是stderr的錯誤提示。i 這個變量都能獲取到一個字符串。
針對答主的問題,應該是如下操作:

i=$(ls 123.txt 2> /dev/null)

  這樣的命令,ls命令如果出現了錯誤提示,就會被重定向到/dev/null垃圾桶去了。所以,i 這個變量就獲取不到stderr標準錯誤的提示字符串了。所以,在這個命令的操作中,i 就只能獲得文件stdout標準輸出,也就是文件述符1的屏幕輸出結果"123.txt"。
  如果,這個123.txt文件不存在,i 就什麼都拿不到,因爲錯誤提示被/dev/null 吃了(劃掉),被重定向丟棄了。所以,i 就是個什麼都沒有的空變量。基本就是如下效果一樣:

i=''
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章