Landscape トップページ | < 前の日 2004-03-27 2004-03-28 次の日 2004-03-30 >

Landscape - エンジニアのメモ 2004-03-28

シェルのリダイレクトにまつわる失敗


* シェルのリダイレクトにまつわる失敗

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [bash]

シェルのリダイレクトについての理解が不十分なためにやってしまった失敗。

標準出力も標準エラー出力も /dev/null に捨てたいとき、間違えて以下のようにしてしまうことがときどきあった。最近はやらなくなったが。
# 間違い
$ command 2>&1 >/dev/null
これだと command の標準出力は /dev/null に向けられるが、command の標準エラー出力は画面に向いてしまう。

正しくは以下のように記述する。こうすることで、両方とも /dev/null に向けられる。
# 正しい
$ command >/dev/null 2>&1

- なぜ間違ってしまうのか?

間違った記述をしてしまう理由は、リダイレクトを誤解しているからだ。そのときの私の思考は以下のようなものだ。
標準エラー出力は2番だから、まず2番を1番が指している先に合流させるために 2>&1 とする。
で、1番を >/dev/null として /dev/null に向ければ、両方とも /dev/null に向く。

ここで問題なのは、2>&1 を「合流」と考えてしまっていることだ。さらに、「2番を1番に合流させているんだから、1番をリダイレクトすれば両者ともに出力先が変わる」と考えてしまっていることだ。実際のリダイレクトはそういった処理はしていない。

- 実際のリダイレクト処理

実際のリダイレクトの処理は、コマンドラインの左から右へ、ファイルディスクリプタをオープン/クローズしながら進められる。以下のサイトの説明を読んだ方が早い。

シェルのファイルディスクリプタ操作
http://home.catv.ne.jp/pp/ginoue/memo/sh-fd.html

まずは正しい例。
ls >outfile.txt 2>&1
また実装例から示します。

fd = open("outfile.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(fd, 1);
close(fd);
dup2(1, 2);
「ls >outfile.txt 2>&1」が左から処理されていく過程を追います。「>outfile.txt」は上と同じで、ファイルを指すfdが作られた後、1番が一旦クローズされてfdの複製として再生され、ついでにfdがクローズされます。「2>&1」は、2番が一旦クローズされて1番の複製として再生されます。


1番 => [screen]
2番 => [screen]
      |
      |  fd = open();
      |  dup2(fd, 1);一旦1番をクローズ。
      |              1番がfdの複製として再生される。
      |  close(fd);
      V
1番 => [file]
2番 => [screen]
      |
      |  dup2(1, 2);一旦2番をクローズ。
      |            2番が1番の複製として再生される。
      V
1番 => [file]
2番 => [file]

結局、1番も2番もファイル(outfile.txt)を指すことになります。つまり、lsの標準出力も標準エラー出力もファイルに出力されます。

次に、私が間違った例。
ls 2>&1 >outfile.txt
いつものように実装例から。

dup2(1, 2);
fd = open("outfile.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(fd, 1);
close(fd);
「2>&1」も「>outfile.txt」も、上で説明したとおりの動作をします。左から処理が進むので、処理の順番が異なるだけですが、最終形態も異なります。


1番 => [screen]
2番 => [screen]
      |
      |  dup2(1, 2);一旦2番をクローズ。
      |            2番が1番の複製として再生される(結局、画面のまま)。
      V
1番 => [screen]
2番 => [screen]
      |
      |  fd = open();
      |  dup2(fd, 1);一旦1番をクローズ。
      |              1番がfdの複製として再生される。
      |  close(fd);
      V
1番 => [file]
2番 => [screen]
(fd => [file])

結局、1番がファイルを指して、2番は画面のままです。

合流とかそういうものではなく、毎回毎回ファイルディスクリプタのオープンとクローズが行われていることがわかる。

- さらにすごい間違い

私がやった失敗をもう一つ。
$ command >/dev/null &2>1

標準エラー出力を1番のファイルディスクリプタに向けようとしたのだが、この記述だとやりたかったこととはまったく違う結果になる。まず、& が指定されているためコマンドはバックグラウンドで実行される。そして2番の標準エラー出力が 1 というファイルに向けられる。

普通ならば「バックグラウンド実行されたよ」という旨のメッセージが表示されるため、すぐに間違いに気づく。しかし、悪いことにこれを crontab に書いていたため、発見が遅れてしまった。cron の結果を確認しようとしたところ、なぜか 1 というファイルができており、そのときになって初めて気づいたのだった。

すべての記事の見出し (全1029件)
全カテゴリの一覧と記事の数
カテゴリごとに記事をまとめ読みできます。記事の表題だけを見たい場合は、すべての記事の見出し (カテゴリ別表示) へ。

直近30日分の記事
2007-04-23 (Mon)
2007-03-07 (Wed)
2007-02-27 (Tue)
2007-01-17 (Wed)
2007-01-15 (Mon)
2007-01-14 (Sun)
2007-01-08 (Mon)
2006-12-01 (Fri)
2006-11-22 (Wed)
2006-11-20 (Mon)
2006-11-19 (Sun)
2006-09-30 (Sat)
2006-08-29 (Tue)
2006-08-04 (Fri)
2006-07-27 (Thu)
2006-07-23 (Sun)
2006-07-17 (Mon)
2006-07-10 (Mon)
2006-07-06 (Thu)
2006-07-03 (Mon)
2006-06-29 (Thu)
2006-06-28 (Wed)
2006-06-27 (Tue)
2006-06-25 (Sun)
2006-06-19 (Mon)
2006-06-18 (Sun)
2006-06-15 (Thu)
2006-06-11 (Sun)
2006-06-01 (Thu)
2006-05-30 (Tue)
プロファイル
斎藤 宏明。エンジニアです。宇都宮市に住んでいます。
リンク
RSS
スポンサードリンク
Powered by
さくらインターネット

© 斎藤 宏明 Saito Hiroaki Gmail Address
Landscape - エンジニアのメモ http://sonic64.com/
Landscape はランドスケープと読みます。
ひらがなだと らんどすけーぷ です。