弄清楚 >/dev/null 2>&1 與 2>&1 >/dev/null 的差異

以前都是硬背起來的,如果要把所有的輸出都丟到 /dev/null,要用前面的方式才會是對的,但其實在 bash 的 manpage 裡面有提到:

Note that the order of redirections is significant. For example, the command

    ls > dirlist 2>&1

directs both standard output and standard error to the file dirlist, while the command

    ls 2>&1 > dirlist

directs only the standard output to file dirlist, because the standard error was duplicated from the standard output before the standard output was redirected to dirlist.

這是因為照順序跑 dup2() 的關係 (參考 bash 的 redir.c)。

前者會先把 dirlist 開起來後透過 dup2() 複製到 fd=1,再用一次 dup2() 把 fd=1 複製到 fd=2,達到我們要的效果。

後者則是先把 fd=1 複製到 fd=2 (於是大家都丟到 stdout 了),接下來再把 dirlist 開起來,丟到 fd=1。這樣變成 ls 寫到 stderr 的東西變成到 stdout 了,而本來寫到 stdout 的東西進到 dirlist 這個檔案裡。

剛剛寫 code 時想找一下有沒有官方文件或是 source code 有描述 ordering 或是有定義行為,結果發現 bash 的 manpage 裡面就有提到了...

當程式沒問題時就會吃掉輸出的 chronic

跑 cron job 的時候,希望程式有問題的時候通知管理者 (或是執行者),這個可以透過 moreutils 內的 chronic 來達成:

chronic - runs a command quietly unless it fails

chronic 會將 stdout 與 stderr 的輸出結果暫存起來,如果程式正常結束 (exit 0) 就不管他,但如果有問題的時候就會 output 出來 (exit 不是 0,或是 crash),而 cron 在收到 stdout/stderr 有東西時,會寄信給管理者或是執行者,這剛好就是我們要的行為。

算是很好用的指令,沒事你不會想管他輸出什麼啊... XD