Linux 输入输出重定向 2>/dev/null和>/dev/null 2>1和2>1>/dev/nul
From:https://www.cnblogs.com/520playboy/p/6275022.html
2>/dev/null? 和? >/dev/null 2>&1? 和? 2>&1>/dev/null :https://blog.csdn.net/zhongqi2513/article/details/78613768
連接遠程機器執行 shell 命令的一個使用示例:
命令:$(nohup python3 ./start.py --slave=weibo_spider >& /dev/null < /dev/null &) && sleep 0.1
背景
在 shell 腳本中經常會發現 >/dev/null 2>&1 這樣的語句。以前并沒有去深入地理解這段命令的作用,照搬照用,直到將這段命令不小心寫成了 2>&1 >/dev/null,出了一點小問題之后,才開始去了解這段命令背后的玄機。
shell 重定向介紹
一段程序在處理完外部的輸入后,會將運算結果輸出到指定的位置。在交互式的程序中,輸入來自用戶的鍵盤和鼠標,結果輸出到用戶的屏幕,甚至播放設備中。而對于某些后臺運行的程序,輸入可能來自于外部的一些文件,運算的結果通常又寫到其他的文件中。而且程序在運行的過程中,會有一些關鍵性的信息,比如異常堆棧,外部接口調用情況等,這些都會統統寫到日志文件里。
shell 腳本也一樣,但是我們一般在使用 shell 命令的時候,更多地還是通過鍵盤輸入,然后在屏幕上查看命令的執行結果。如果某些情況下,我們需要將 shell 命令的執行結果存儲到文件中,那么我們就需要使用輸入輸出的重定向功能。
文件描述符
當執行 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 指向文件,那么標準的輸出就會輸出到文件中。
/dev/null 代表 linux 的空設備文件,所有往這個文件里面寫入的內容都會丟失,俗稱 "黑洞"
關于? ”&”? 的作用
這里的 & 沒有固定的意思
放在 > 后面的 & ,表示重定向的目標不是一個文件,而是一個文件描述符,內置的文件描述符如下1 => stdout2 => stderr0 => stdin2>1 代表將 stderr 重定向到當前路徑下文件名為 1 的 regular file中, 2>&1 代表將 stderr 重定向到文件描述符為 1 的文件(即/dev/stdout)中,這個文件就是stdout在file system中的映射&>file 是一種特殊的用法,也可以寫成 >&file,二者的意思完全相同 都等價于 >file 2>&1此處 &> 或者 >& 視作整體,分開沒有單獨的含義我們可以這么理解? 2>/dev/null? 重定向到文件,那么? 2>&1,這里如果去掉了&就是把錯誤輸出給了文件1了,用了&是表明 1 是標準輸出。
第二個問題:
? ? find /etc -name .bashrc > list 2>&1
? ? # 我想問為什么不能調下順序,比如這樣
? ? find /etc -name .bashrc 2>&1 > list
? ? 這個是從左到右有順序的
?? ?
第一種
? ? xxx > list 2>&1
? ? 先將要輸出到stdout的內容重定向到文件,此時文件list就是這個程序的stdout,
? ? 再將stderr重定向到stdout,也就是文件list
第二種
? ? xxx 2>&1 > list
? ? 先將要輸出到stderr的內容重定向到stdout,此時會產生一個stdout的拷貝,作為程序的stderr,
? ? 而程序原本要輸出到stdout的內容,依然是對接在stdout原身上的,
? ? 因此第二步重定向stdout,對stdout的拷貝不產生任何影響
關于shell中:>/dev/null 2>&1 詳解
? ? ? ? shell中可能經常能看到:>/dev/null 2>&1 。命令的結果可以通過%>的形式來定義輸出
? ? ? ? 分解這個組合:“>/dev/null 2>&1” 為五部分。
? ? ? ? ? ? ? ? 1:> 代表重定向到哪里,例如:echo "123" > /home/123.txt
? ? ? ? ? ? ? ? 2:/dev/null 代表空設備文件
? ? ? ? ? ? ? ? 3:2> 表示stderr標準錯誤
? ? ? ? ? ? ? ? 4:& 表示等同于的意思,2>&1,表示 2 的輸出重定向等同于 1
? ? ? ? ? ? ? ? 5:1 表示stdout標準輸出,系統默認值是1,所以">/dev/null"等同于 "1>/dev/null"
? ? ? ? 因此,>/dev/null 2>&1也可以寫成 “ 1> /dev/null 2> &1 ”
那么?&>/dev/null 語句執行過程為:
1>/dev/null :首先表示標準輸出重定向到空設備文件,也就是不輸出任何信息到終端,說白了就是不顯示任何信息。
2>&1 :接著,標準錯誤輸出重定向 到標準輸出,因為之前標準輸出已經重定向到了空設備文件,所以標準錯誤輸出也重定向到空設備文件。
輸出重定向
輸出重定向的使用方式很簡單,基本的一些命令如下:
| command >filename | 把標準輸出重定向到新文件中 |
| command 1>filename | 同上 |
| command >>filename | 把標準輸出追加到文件中 |
| command 1>>filename | 同上 |
| command 2>filename | 把標準錯誤重定向到新文件中 |
| command 2>>filename | 把標準錯誤追加到新文件中 |
我們使用>或者>>對輸出進行重定向。符號的左邊表示文件描述符,如果沒有的話表示1,也就是標準輸出,符號的右邊可以是一個文件,也可以是一個輸出設備。當使用>時,會判斷右邊的文件存不存在,如果存在的話就先刪除,然后創建一個新的文件,不存在的話則直接創建。但是當使用>>進行追加時,則不會刪除原來已經存在的文件。
為了更好地理解輸出重定向,感受重定向的“魅力”,我們看一下以下的例子:我們創建一個測試目錄,目錄下面僅有一個a.txt文件。
# tree . └── a.txt 0 directories, 1 file# ls a.txt b.txt ls: 無法訪問b.txt: 沒有那個文件或目錄 a.txt執行?ls a.txt b.txt之后,共有兩種輸出,其中ls: 無法訪問b.txt: 沒有那個文件或目錄是錯誤輸出,a.txt是標準輸出。
# 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: 沒有那個文件或目錄看到這里,朋友們可能會發現>out 2>err和我們在一開頭提到的>/dev/null 2>&1已經很像了,別急,這待會再說。
輸入重定向
在理解了輸出重定向之后,理解輸入重定向就會容易得多。對輸入重定向的基本命令如下:
| command <filename | 以filename文件作為標準輸入 |
| command 0<filename | 同上 |
| command <<delimiter | 從標準輸入中讀入,直到遇到delimiter分隔符 |
我們使用<對輸入做重定向,如果符號左邊沒有寫值,那么默認就是0。
我們這次以cat命令為例,如果cat后面沒有跟文件名的話,那它的作用就是將標準輸入(比如鍵盤)回顯到標準輸出(比如屏幕)上:
# cat123 123 test test我們可以將利用輸入重定向,將我們在鍵盤上敲入的字符寫入到文件中。我們需要使用ctrl+c來結束輸入:
# cat >out 123 test ^C# cat out 123 test好了,此時我們覺得自己在鍵盤上敲比較累,還是直接讓cat讀取一個文件吧。那么我們需要利用輸入重定向:
# cat input aaa 111# cat >out <input # cat out aaa 111神奇的事情發生了,out文件里面的內容被替換成了input文件里的內容。那么<<又是什么作用呢?我們再看:
# cat >out <<end > 123 > test > end# cat out 123 test我們看到,當我們輸入完cat >out <<end,然后敲下回車之后,命令并沒有結束,此時cat命令像一開始一樣,等待你給它輸入數據。然后當我們敲入end之后,cat命令就結束了。end之前輸入的字符都已經被寫入到了out文件中。這就是輸入分割符的作用。
高級用法
重定向綁定
好了,在有了以上知識的基礎上,我們再來看開頭提到的?>/dev/null 2>&1。
這條命令其實分為兩命令,一個是?>/dev/null,另一個是?2>&1?。
1. >/dev/null
這條命令的作用是將標準輸出1重定向到/dev/null中。/dev/null代表linux的空設備文件,所有往這個文件里面寫入的內容都會丟失,俗稱“黑洞”。那么執行了>/dev/null之后,標準輸出就會不再存在,沒有任何地方能夠找到輸出的內容。
2. 2>&1
這條命令用到了重定向綁定,采用&可以將兩個輸出綁定在一起。這條命令的作用是錯誤輸出將和標準輸出同用一個文件描述符,說人話就是錯誤輸出將會和標準輸出輸出到同一個地方。
linux在執行shell命令之前,就會確定好所有的輸入輸出位置,并且從左到右依次執行重定向的命令,所以>/dev/null 2>&1的作用就是讓標準輸出重定向到/dev/null中(丟棄標準輸出),然后錯誤輸出由于重用了標準輸出的描述符,所以錯誤輸出也被定向到了/dev/null中,錯誤輸出同樣也被丟棄了。執行了這條命令之后,該條shell命令將不會輸出任何信息到控制臺,也不會有任何信息輸出到文件中。
>/dev/null 2>&1? ? VS? ? 2>&1 >/dev/null
再回到文章的開頭,我說我弄反了>/dev/null和2>&1拼裝的順序,導致出了一點小問題。乍眼看這兩條命令貌似是等同的,但其實大為不同。剛才提到了,linux在執行shell命令之前,就會確定好所有的輸入輸出位置,并且從左到右依次執行重定向的命令。那么我們同樣從左到右地來分析2>&1 >/dev/null:
我們用一個表格來更好地說明這兩條命令的區別:
| >/dev/null 2>&1 | 丟棄 | 丟棄 |
| 2>&1 >/dev/null | 丟棄 | 屏幕 |
>/dev/null 2>&1? ? VS? ? >/dev/null 2>/dev/null
那么可能會有些同學會疑問,為什么要用重定向綁定,而不是像>/dev/null 2>/dev/null這樣子重復一遍呢。
為了回答這個問題,我們回到剛才介紹輸出重定向的場景。我們嘗試將標準輸出和錯誤輸出都定向到out文件中:
# ls a.txt b.txt >out 2>out # cat out a.txt �法訪問b.txt: 沒有那個文件或目錄WTF?竟然出現了亂碼,這是為啥呢?這是因為采用這種寫法,標準輸出和錯誤輸出會搶占往out文件的管道,所以可能會導致輸出內容的時候出現缺失、覆蓋等情況?,F在是出現了亂碼,有時候也有可能出現只有error信息或者只有正常信息的情況。不管怎么說,采用這種寫法,最后的情況是無法預估的。
而且,由于out文件被打開了兩次,兩個文件描述符會搶占性的往文件中輸出內容,所以整體IO效率不如>/dev/null 2>&1來得高。
nohup結合
我們經常使用nohup command &命令形式來啟動一些后臺程序,比如一些java服務:# nohup java -jar xxxx.jar &
為了不讓一些執行信息輸出到前臺(控制臺),我們還會加上剛才提到的>/dev/null 2>&1命令來丟棄所有的輸出:
# nohup java -jar xxxx.jar >/dev/null 2>&1 &
總結
本文主要介紹了linux重定向的原理以及一些基本命令,并且詳細地分析了>/dev/null 2>&1這個命令以及一些注意點。
總而言之,在工作中用到最多的就是nohup command >/dev/null 2>&1 &命令,希望大家能夠好好掌握。
參考資料
總結
以上是生活随笔為你收集整理的Linux 输入输出重定向 2>/dev/null和>/dev/null 2>1和2>1>/dev/nul的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot 自带工具类~Aop
- 下一篇: 简明Python教程学习笔记_6_面向对