SSブログ

出力リダイレクトによくある問題 [概論・概要]

 前回アーティクルからの続き。

 今回は、「出力リダイレクト」によくある問題を取り上げたい。ほんのちょっとだけ敷居が高くなる(かもしれない)が、がんばって理解に努めてほしい。

その1:標準出力と、標準エラー出力とを「同じファイル」に出力したい。
 前回のアーティクルで、wcコマンドの出力結果を「wckekka.txt」と「wcerror.txt」と、異なるファイルに出力した。
 その時のコマンド入力はこうだった。

 wc -l bindir.txt > wckekka.txt 2> wcerror.txt

 時には、この両方の結果を「同じファイルに出力したい」という要望に遭遇する事がありうる。
 その場合は、標準出力と標準エラー出力とを同じファイルに出力するように指定することで解決ができる。難しい話ではない。

 wc -l bindir.txt > wckekka.txt 2> wckekka.txt

 ただ、この方法で指定する人はほとんどいないのである。なぜなら、同じファイル名を2回も記述していてスマートでは無いからである。
 このサンプルの場合は、相対パス指定でファイル名しか指定していないが、時と場合によっては絶対パス指定で深いディレクトリの中に記録したい場合とか現れてしまったら…

 wc -l /home/piro791/stdio/bindir.txt > /var/tmp/fukai/fukai/directory/no/sarani/oku/wckekka.txt 2> /var/tmp/fukai/fukai/directory/no/sarani/oku/wckekka.txt

 などということになってしまい、全くもって面倒臭いことになってしまうから。
 そこで、UNIX時代の偉い人は、

 以下同文

 的な指定方法を編み出してくれたのであった。ありがたやありがたや…。
 それが、

 &1
 と
 &2

 という記号なのでした。この記号をつかって、標準出力と標準エラー出力とを同じwckekka.txtに記録するという場合はこうなる。

 wc -l bindir.txt > wckekka.txt 2> &1

 と、指定することになる。すると、
 ・標準出力は「wckekka.txt」に出力
 ・標準エラー出力は標準出力と同じ場所に出力
 ということになる。これなら簡単だ。ありがたやありがたや…。

 ところで、この指定方法には1つ注意すべき落とし穴がある。それを紹介しておく。
 通常、標準出力の出力先を指定する記号と、標準エラー出力の出力先を指定する記号は、どちらを先に指定しても構わないのである。例えば、

 wc -l bindir.txt > wckekka.txt 2> wcerror.txt

 は、

 wc -l bindir.txt 2> wcerror.txt > wckekka.txt

 と、書いても一向に構わないのが原則なのだ。「それじゃあ…」とばかりに、

 wc -l bindir.txt > wckekka.txt 2> &1

 を

 wc -l bindir.txt 2> &1 > wckekka.txt

 と、書いてしまうと、望んだ通りの結果にならないのである。(ただし、エラーにはならない

 どういうことかー?

 実は、&1 とか&2 とかいう記号が登場した場合、その時点で指定されている出力先に変更するという意味を持っているから。
 通常、入力されたコマンドは、左から右に向かって解釈される。つまり、

① wc -l bindir.txt
 →ふむふむ。bindir.txtのファイルの行数を数えればいいのね…
 ※この時点では標準出力も標準エラー出力も「画面に出力する」という状態になっている。

② 2> &1
 →ふむふむ。標準エラー出力は、標準出力と同じ所に出力すればいいのね。今の標準出力の出力先は「画面に出力」か。じゃあ標準エラー出力は「画面に出力」すればいいのね。

③ > wckekka.txt
 →標準出力はファイル「wckekka.txt」に出力するのね。了解した。

 …という具合に解釈されてしまい、標準エラー出力と標準出力とは異なる出力先に出力されてしまうことになる。
 これが正しい順序で指定されていた場合はどうなるのかといえば、

 wc -l bindir.txt > wckekka.txt 2> &1

①wc -l bindir.txt
 →ふむふむ。bindir.txtのファイルの行数を数えればいいのね…
 ※この時点では標準出力も標準エラー出力も「画面に出力する」という状態になっている。

② > wckekka.txt
 →標準出力はファイル「wckekka.txt」に出力するのね。了解した。

③ 2> &1
 →ふむふむ。標準エラー出力は、標準出力と同じ所に出力すればいいのね。今の標準出力の出力先はファイル「wckekka.txt」に出力か。じゃあ標準エラー出力も「wckekka.txt」に出力するぞ。

 …と、なるのであった。これは重要な問題なのでよーく覚えておくように。

 ちなみに、「&2」はというと、これは「標準エラー出力と同じ」という意味になる。標準出力を「標準エラー出力と同じ」場所に出力したい場合に使う。つまり…

 wc -l bindir.txt 2> wckekka.txt > &2

 というような使い方をすることになるのだが、こんな指定をする人はまず変態だと思って差し支えないと思われる。…というくらいドマイナーな使い方だということ。(笑)

その2:標準出力と、標準エラー出力を破棄したいが、ファイルも残したくない。
 標準出力や標準エラー出力をファイルに記録するようにリダイレクトすると、コマンド自体は無言で実行されることになる。出力結果がどうであれ、あるいはエラーが有ろうが無かろうが、その結果は全てファイルに記録されるので、画面上には何も表示されないことになる。
 ある種の処理を実施する場合、このように無言で動作してくれることが望ましいという場合もある。
 かといって、いちいちファイルに出力されては後始末も面倒くさい。なにか良い方法はないものか?

 と、お嘆きのアナタ!そんなアナタにピッタリのリダイレクト先があります!!
 それが…

 /dev/null

 というファイルです。
 この「/dev/null」というファイルは、非常に特殊なファイルで、特に「デバイスファイル」という分類に属します。laコマンドでちょっと確認してみましょう。
[piro791@urd stdio]$ ls -l /dev/null
crw-rw-rw- 1 root root 1, 3 11月  9 19:05 2012 /dev/null
[piro791@urd stdio]$

 ファイルサイズの部分がなんだか変です。「1,3」とかいう謎の表示になっています。これは、「デバイス番号」という特殊な情報を示していますが、今はまあ「そういう物があるんだ…」程度の理解で一向に構いません。
 このファイルをcatコマンドで覗いてみましょう。すると…
[piro791@urd stdio]$ cat /dev/null
[piro791@urd stdio]$

 中身はカラッポです。

 では、試しにlsコマンドの結果を/dev/nullに出力するようにしてみましょう。
[piro791@urd stdio]$ ls -la /bin > /dev/null 2>&1
[piro791@urd stdio]$

 lsコマンドが無言です。
 では、再度/dev/nullをcatコマンドで覗いてみます。
[piro791@urd stdio]$ cat /dev/null
[piro791@urd stdio]$

 なんと、やっぱりカラッポじゃないですか。
 このように、/dev/nullは何でも吸い込んでしまい、何も出てこられないUNIX/Linux界のブラックホール的な存在になっています。(笑)

その3:標準出力や標準エラー出力の内容をファイルに「追加」したい。
 実は、これまでに説明した出力リダイレクトというものは、コマンドを実行する度にファイルを上書きしてしまうものでした。
 例えば、(lsコマンドで試すと長くて判りにくいので)サーバの日時を表示するdateコマンドで解説すると…
[piro791@urd stdio]$ date > hiduke.txt
[piro791@urd stdio]$ date > hiduke.txt
[piro791@urd stdio]$ date > hiduke.txt
[piro791@urd stdio]$ cat hiduke.txt
2012年 11月 15日 木曜日 15:06:20 JST
[piro791@urd stdio]$

 dateコマンドを3回、同じファイルに出力するように指定して実行しているが、cat コマンドで確認が出来るのは最後の1回分だけになっている。つまり、dateコマンドを実行する度にhiduke.txtファイルを上書きしてしまっているということになる。
 しかし、時と場合によっては「追加で書き込みがしたい」ということもあり得る。そのような場合はどうすればよいだろう?

 答えは、「>」を2個重ねて指定するのである。つまり、

 >>
 とか、
 2>>

 とかいう具合に記述すると、その時は「ファイルに追加書き込み」が行われるのである。(※なお、指定されたファイルが存在しない場合は、新しく作成して先頭から書き込みが行われるという親切設計である。
[piro791@urd stdio]$ ls -la
合計 20
drwxrwxr-x 2 piro791 piro791 4096 11月 15 15:06 2012 .
drwx------ 3 piro791 piro791 4096 11月 15 10:19 2012 ..
-rw-rw-r-- 1 piro791 piro791 6497 11月 15 10:59 2012 bindir.txt
-rw-rw-r-- 1 piro791 piro791   43 11月 15 15:06 2012 hiduke.txt
[piro791@urd stdio]$

 このような状態の時に、dateコマンドを3回実行して、「hiduke2.txt」に追加書き込みで出力してみる。すると…
[piro791@urd stdio]$ date >> hiduke2.txt
[piro791@urd stdio]$ date >> hiduke2.txt
[piro791@urd stdio]$ date >> hiduke2.txt
[piro791@urd stdio]$ cat hiduke2.txt
2012年 11月 15日 木曜日 15:11:34 JST
2012年 11月 15日 木曜日 15:11:38 JST
2012年 11月 15日 木曜日 15:11:42 JST
[piro791@urd stdio]$

 …と、確かに3回分のdateコマンドの結果が出力されていることが判る。
 なお、標準エラー出力も全く同じ要領なので、ここでは省略する。


 次回のアーティクルは、標準出力と標準入力とを連結する手法「パイプ」について説明したい。
nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。