いい加減、>/dev/null 2>&1と書くのをやめたらどうか (追記あり)

シェルスクリプトやcrontab(注1)で標準出力と標準エラー出力の両方を捨たいときは、一般にこのように書きます。
command >/dev/null 2>&1
この記法、本当に覚える必要あるでしょうか?

(注1:そもそもcrontabの出力は捨てない方がよいです。追記1をご覧ください。)
(注2:結論から言うと、覚える必要あります。追記2をご覧下さい。)

はじめに

これから書く内容は、シェルスクリプトをばりばり書いている現場(サーバエンジニア・インフラエンジニア)向けのものではありません。
年に数回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の出力を捨てるのはよくない」とのご指摘をいただきました。
今まで何も考えずに捨ててましたが、たしかによく考えると捨てるのはよくない気がしてきました。

cron で > /dev/null して椅子を投げられないための3つの方法 - 酒日記 はてな支店

ご指摘ありがとうございます!

追記2:この方法は/dev/nullのときしか使えない


実際にやってみました。
$ perl -e 'print "1\n" ; warn "2\n";' 1>a.txt 2>a.txt
$ cat a.txt
1
た、たしかに片方しか残ってない・・・。

ご指摘ありがとうございました!
カテゴリ:

人気記事