若是一個命令須要長時間在服務器上運行,那麼不少時候會用到nohup命令,這時即使遠程登陸ssh中斷了與服務器的聯繫,那麼在服務器上運行的命令也不會所以而被迫中止。shell
一般狀況下,nohup與&連用,&的意思是將該命令放在後臺執行。以下:bash
nohup example.sh &
將exmaple.sh經過&放在服務器後臺運行,nohup確保了即使當前ssh遠程鏈接中斷,example.sh仍然可以不受影響,繼續在遠程服務器中運行。服務器
最近有兩個配對測序文件,須要比對到參考基因組上,經過bwa能夠完成,同時因爲該文件比較大,運行時間長,爲了不網絡鏈接不穩定形成ssh中斷,使用nohup網絡
nohup bwa mem ref.fa read1.fq.gz read2.fq.gz > read12.sam &
將兩個測序文件合併並生成sam文件。
寫好命令,一個回車鍵按下去,「啪」一聲,那就一個爽。而後不用管它,十餘個小時以後,果真生成了一個很大的文件read12.sam文件。
可是,當用該sam文件生成bam文件時,提示錯誤sam文件存在錯誤!!!【十餘個小時的計算白費了】
仔細檢查了一下sam文件,發現程序運行的結果和程序運行過程當中的說明輸出到了同一個文件中!app
標準輸出(standard output)即結果默認的輸出地方,好比在bash中,ssh
$ echo 'hello' hello
在默認狀態下,’hello’時輸出到你的終端(terminal)上顯示。
再如,經過cat命令顯示一個文本文件,ide
$ cat hello.txt Hello! This is a test!
可是,若是這個文本文件在當前路徑下不存在,在會輸出錯誤:this
$ cat No_exist.txt
cat: No_exist.txt: No such file or directory
這時的輸出內容「cat: No_exist.txt: No such file or directory」就是標準錯誤(standard error)。code
默認狀況下,標準輸出和標準錯誤都會在終端顯示。若是要將標準輸出不是輸出在終端,而是輸出到一個其餘文件中,這個時候就是重導向輸出,能夠經過「>「符號來完成。ip
echo 'hello' > hello.txt
將「hello」輸出到hello.txt文件中,系統會新建立該文件,若是路徑中存在該文件,舊的文件將會被覆蓋。
還可使用」>>」符號,這樣不會覆蓋舊文件,會將」hello」添加到舊文件中。
那麼,這兒有一個問題,是否是全部輸出到終端的內容均可以重導向輸出到一個文件中?好比,若是是標準錯誤,可否經過」>」輸入到文件中?
$ cat No_exist.txt > output.txt cat: No_exist.txt: No such file or directory
結果證實:不能!output.txt依舊是一個空文件,而錯誤內容並無出如今該文件中,依舊在終端顯示!因此不能直接經過」>」將標準錯誤輸出到文件中!
那麼應該怎樣才能將標準錯誤輸出到文件中呢?
在bash中,一般使用3個整數來表示標準輸入(0)、標準輸出(1)和標準錯誤(2)。
若是要把標準錯誤輸出到文件中,可使用
cat No_exist.txt 2> tt.txt
這時在tt.txt文件中就會出現標準錯誤「cat: No_exist.txt: No such file or directory」。
一樣的道理,咱們能夠將標準錯誤重導向輸出爲標準輸出,2>&1
好比
$ cat No_exist.txt cat: No_exist.txt: No such file or directory $ cat No_exist.txt 2>&1 cat: No_exist.txt: No such file or directory
雖然它們在終端上輸出的內容看起來沒有什麼區別,可是它們的身份是不同的,第一個是以標準錯誤的形式輸出的,而第二個是標準輸出。咱們能夠經過管道符號驗證一下它們的不一樣。
$ cat No_exist.txt | sed 's/or/and/' cat: No_exist.txt: No such file or directory $ cat No_exist.txt 2>&1| sed 's/or/and/' cat: No_exist.txt: No such file and directory
如今能夠看出區別了,第一個標準錯誤沒法經過管道符號把「or」替換成「and」,而第二個是標準輸出,能夠經過管道符號,把其中的「or」替換成「and」.
一樣的道理,也能夠將標準輸出重導向爲標準錯誤「1 >2&「
那麼回過頭來,看最開始的那個問題,爲何nohup同時會運算結果和運算過程的描述輸出到同一個sam文件中呢?
爲了簡便,用下面的代碼(example.sh)重現了nohup中的錯誤。
#!/bin/bash echo "this is outcome!" sleep 1 echo "sleep for 1s" >&2 echo "this is outcome, too!" sleep 2 echo "second sleep for 2s" >&2
其中sleep的過程描述經過 >&2以標準錯誤的形式出現,而outcome則以標準輸出的形式輸出。
正常狀況下,運行:
$ ./example.sh > outcome.txt sleep for 1s second sleep for 2s $ cat outcome.txt this is outcome! this is outcome, too!
標準錯誤直接輸出到了終端中,運行結果輸出到了outcome.txt中,沒有任何問題。可是在nohup的狀況下,這種狀況就變了。
在nohup的說明中,提到「若是標準輸出是在終端,那麼輸出的內容將會被添加到‘nohup.out’文件中;若是標準錯誤的輸出是在終端,那麼內容將會被重導向到標準輸出「。這就意味着,在沒有特殊說明的狀況下,標準輸出和標準錯誤將會被重導向輸出到同一個地方。以下,
$ nohup ./example.sh appending output to nohup.out $ cat nohup.out this is outcome! sleep for 1s this is outcome, too! second sleep for 2s
在nohup.txt文件中不只出現了我想要的運行結果,還出現了我不想要的運行過程!這也就解釋了爲何在個人sam文件中會出現不少本不該該屬於該文件的內容。
既然知道了緣由,那麼解決問題就不難了。咱們能夠經過重導向輸出,把運行結果和運行過程分別輸出到不一樣的文件中。
$ nohup ./example.sh 2>stderr.log 1>outcome.txt $ cat stderr.log sleep for 1s second sleep for 2s $ cat outcome.txt this is outcome! this is outcome, too!
這樣,將過程以標準錯誤形式輸出到stderr.log中,將結果以標準輸出形式輸出到outcome.txt中。
因此本文最開頭提到的命令能夠改成:
nohup bwa mem ref.fa read1.fq.gz read2.fq.gz 1> read12.sam 2>read12.log &
nohup在默認條件下,標準錯誤和標準輸出會重導向到同一個文件中;經過文件描述符(0,1,2)來對控制輸出內容;養成良好的輸出控制習慣,對標準輸出和標準錯誤要區別對待。
===== THE END =====
參考資料:
https://robots.thoughtbot.com/input-output-redirection-in-the-shell#file-descriptors
https://www.brianstorti.com/understanding-shell-script-idiom-redirect/