いい加減、>/dev/null 2>&1と書くのをやめたらどうか (追記あり)
はじめに
これから書く内容は、シェルスクリプトをばりばり書いている現場(サーバエンジニア・インフラエンジニア)向けのものではありません。年に数回crontabをいじるような現場(サーバに詳しくないアプリケーションプログラマが多数を占めるような現場とか、Webデザイナや非プログラマがcrontabをおそるおそるいじったりするような現場)を想定しています。
>/dev/null 2>&1 の問題点
この記法の問題点は、「覚えにくい、間違えやすい、間違ってても気づかない」ということです。初心者を迷わせる要素がこんなにあります。
- >/dev/nullは先か後か
- 1と2はどちらが先か
- &はどこに書くのか
- 2>&1 >/dev/null
- >/dev/null 1>&2
- >/dev/null 2>1&
- >/dev/null &2>1
さらに被害を大きくしているのは、この記述をcrontabに書くことが多いということです。
(crontabのログ出力を捨てるなとのご指摘をいただきました。追記1をご覧ください。)
間違える人が多い = インターフェースが悪い
ちょっとGoogleで検索するだけでも、「間違えて失敗した」「間違えてたことに後で気づいた」という例が腐るほど出てきます。間違える人が多いということは、人間が悪いのではなく、ユーザインターフェースの設計が悪いと言わざるをえません。
「>/dev/null 2>&1」と書く理由について、ファイルディスクリプタやシェルの仕組みまで遡って解説しているサイトをよくみかけます。
ファイルディスクリプタやシェルの内部の仕組みに精通することそれ自体は素晴らしいことだし、やる気があるなら勉強した方がいいと思います。
ですが、「ファイルディスクリプタの挙動を知らないと間違えてしまう」というのはいかがなものでしょうか。
「出力を捨てたい」という単純な目的のために、そこまで勉強しないといけないのでしょうか。
「内部の詳細を知らなくても使えるようにカプセル化しろ、インターフェースをきれいにしろ」とは、オブジェクト指向の世界でさんざん言われてきたはずです。
jQueryにしてもRailsにしても、内部詳細を知らなくても使えるからこそ「生産性が高い」と言われるのではないでしょうか。
代替案
そこで、こんな書き方を提案します。command 1>/dev/null 2>/dev/null
いかがでしょう?この記法のメリット
- 1と2の順番を逆にしても問題なく動く。
- &が登場しない。
- 出力先をファイルにしたくなったときに、簡単に変更できる。
(注:1>a.txt 2>a.txtの場合、正しく動きません。追記2をご覧ください。)
- 1が標準出力、2が標準エラー出力
- >はリダイレクト
- /dev/null = 虚無
プログラミング言語で例えてみる
2つの記法の違いを、プログラミング言語で例えてみましょう。func({1: null, 2: null});
JavaScriptでこのような関数呼び出しの仕様があったとします。すると、「1にnullを、2にもnullを設定している。順番はどちらが先もでもよい」 ということは、ぱっと見てわかりますね。
一方、
func(null, {1:"&2"});
このような関数仕様を見たらどう思うでしょうか?あなたはきっと、「何と汚いAPIか」とライブラリ作者をののしるでしょう。
>/dev/null 2>&1 をちゃんと理解すべきなのはどういうときか
シェルスクリプトを本格的に書くようになると、echo "error message" 1>&2
のように&を使わざるを得ない場面が出てきます。そのときに、&の意味やシェルのリダイレクトの神髄をちゃんと勉強すればよいのではないでしょうか。
(ファイルに出力したい場合は、覚える必要がありそうです。追記2をご覧ください。)
まとめ
command 1>/dev/null 2>/dev/null
と書いた方が人にやさしい。そんなあなたに、くろんメーカ をお勧めします!
(注:1>a.txt 2>a.txtの場合、正しく動きません。追記2をご覧ください。)
「奥が深い症候群」について
>/dev/null 2>&1は「奥が深い症候群」なのか?追記1:cronの出力は捨てない方がよい
crontabに > /dev/null 書いたら椅子投げる
— fujiwara (@fujiwara) June 12, 2012
「crontabの出力を捨てるのはよくない」とのご指摘をいただきました。
今まで何も考えずに捨ててましたが、たしかによく考えると捨てるのはよくない気がしてきました。
cron で > /dev/null して椅子を投げられないための3つの方法 - 酒日記 はてな支店
ご指摘ありがとうございます!
追記2:この方法は/dev/nullのときしか使えない
ダメ。なぜなら > a.txt 2>&1 と 1> a.txt 2> a.txt は意味が違うから。後者の場合、標準出力の内容は a.txt に残らない / "いい加減、>/dev/null 2>&1と書くのをやめたらどうか - DQ..." htn.to/LD5FWX
— Kazuho Oku (@kazuho) June 13, 2012
実際にやってみました。
$ perl -e 'print "1\n" ; warn "2\n";' 1>a.txt 2>a.txt
$ cat a.txt
1
た、たしかに片方しか残ってない・・・。ご指摘ありがとうございました!