バッチ開発でcrontabの設定を眺めていると
1 |
0 * * * * sh hogehoge.sh > /dev/null 2>&1 |
という記述が目に入ることがあると思う。ものすっごくざっくり解説すると、バッチ実行時にエラーやecho等の出力を一切出ないようにするという設定なのだが、自分の備忘録としての意味合いも込めて解説メモを残しておく。
リダイレクト(>)を理解する
1 |
sh hogehoge.sh > /dev/null 2>&1 |
↑の“>”はリダイレクトといい、別の場所に出力内容を渡すことができる記述。
たとえばhoge.shというシェルスクリプトに
1 |
echo 'aaa' |
という出力が書かれていたとする。これをcliで実行すると
1 2 3 |
$ sh hoge.sh aaa $ |
となる。この出力内容を他のファイル(ここではfuga.txtとする)に吐き出させたいと思ったら、下記のようにリダイレクトを活用することで実現可能だ。
1 2 3 4 |
$ sh hoge.sh > result.txt $ cat result.txt aaa $ |
実際の開発現場だと、ログファイルを解析して必要な情報だけ抽出したものをテキストベースに吐き出したい時にリダイレクトはよく使われる。
ファイルディスクリプタ(0,1,2)を理解する
1 |
sh hogehoge.sh > /dev/null 2>&1 |
↑の2や1はファイルディスクリプタといい、
- 標準出力 (stdout: standard output)
- 標準エラー出力 (stderr: standard error)
を意味する。ちなみに0もあり、こちらは標準入力(stdin: standard input)を意味する。これら3つを標準ストリームといい、UNIXやUnix系OS(LinuxやMac等)に予め備わっている入出力チャネルである。
噛み砕くと、echo等で表示する内容は標準出力(1)に、プログラムのエラー等で吐き出される内容は標準エラー出力(2)に渡されるようになっているのだ。
出力の種類に応じてリダイレクトを適切に扱う
標準出力だけをリダイレクトさせて指定のテキストファイルへ書き出したい場合を考える。たとえば存在するファイル(AAA.txt)の名前をresult1.txtに出力させてみよう。
1 2 3 4 |
$ ls AAA.txt > result1.txt $ cat result1.txt AAA.txt $ |
これは標準出力をresult.txtへリダイレクトしており、より詳細に書くと
1 2 3 4 |
$ ls AAA.txt 1> result2.txt $ cat result2.txt AAA.txt $ |
と同じことをしている。つまり、1>と書くと標準出力だけをresult1.txtへ出力させるということなのだ。上記の書き方から分かるように、1>の1は省略することが可能だ。
次に、標準エラー出力だけをリダイレクトさせて指定のテキストファイルへ書き出したい場合を考える。具体的には存在しないファイル(BBB.txt)の名前をresult2.txtに出力させてみよう。
1 2 3 4 |
$ ls BBB.txt 1> result2.txt ls: BBB.txt: No such file or directory $ cat result2.txt $ |
さっきと同じ書き方だとうまくいかないが、標準エラー出力のファイルディスクリプタが2であることを考慮すると下記のようになる:
1 2 3 4 |
$ ls BBB.txt 2> result2.txt $ cat result2.txt ls: BBB.txt: No such file or directory $ |
つまり、2>と書くと標準エラー出力だけをresult2.txtへ出力させることができる。
&を併用することで、特定の出力を指定した出力へマージする
さっきうまく書き出せなかった
1 2 3 4 |
$ ls BBB.txt 1> result2.txt ls: BBB.txt: No such file or directory $ cat result2.txt $ |
という標準エラーが出力される内容を、標準出力へマージして書き出させることもできる。そこで登場するのが&だ。具体的には下記のように書くことで実現できる:
1 2 3 4 |
$ ls BBB.txt 1> result2.txt 2>&1 $ cat result2.txt ls: BBB.txt: No such file or directory $ |
なるほど便利。ここまでくればあと一息だ。
/dev/nullという、ゴミ箱のような意味合いのスペシャルファイル
UNIXやUnix系OS(LinuxやMac等)にはスペシャルファイルと呼ばれる、「普通のファイルとは違うぜ」的なファイルが存在する。/dev/nullもスペシャルファイルの1つで、そこに書き込まれた内容を全て捨て去るという挙動をする。その振る舞いからブラックホールと呼ぶこともある。
出力のリダイレクト先を/dev/nullにすると、あらゆる出力を捨て去るという動きにすることが可能だ。
1 2 |
$ ls BBB.txt 1> /dev/null 2>&1 $ |
↑このような指定の仕方で実現できる。省略して書けば
1 2 |
$ ls BBB.txt > /dev/null 2>&1 $ |
という感じになる。
以上のことから、crontabに
1 |
0 * * * * sh hogehoge.sh > /dev/null 2>&1 |
と書いていたら、shの実行によるあらゆる出力をどこにも書き出さずに処理を終了させている所作になるわけだ。
ただ、本番環境におけるバッチの実運用では何らかのエラーやデバッグがあったら出力&検知できるようにさせておくのが定石だと思うので、基本的にcrontabの記述で > /dev/null 2>&1 を書くことはよほどの例外を除き、あり得ないと心得よう。