SSブログ

標準入力と標準出力、そして標準エラー出力 [概論・概要]

 概論・概略的なお話が続くと、どーしても退屈で眠くなるものですが、UNIX/Linuxを理解する上ではどーしても避けて通れないものなので、もうちょっと我慢しましょう。(笑)

 今回は、「標準入力」「標準出力」「標準エラー出力」について解説します。

 まず、passwdコマンドを思い出してもらいたい。
 passwdコマンドは、ログインパスワードを変更するコマンドだったが、
Changing password for user piro791.
Changing password for piro791
(current) UNIX password:

 というように、「パスワードを変更しますよ。現在のパスワードを入力してください。」  というような表示を画面上に出力をしている。そして、現在のパスワードや新しいパスワードをキーボードから入力している。
 lsコマンドのように、キーボードからの入力を必要としないコマンドもあるが、多くのコマンドは

 ・入力
 ・出力

 を伴う物がほとんどだ。
 そして、ほとんどのケースでは「入力」と言えばキーボードからするものと相場が決まっているし、「出力」といえば画面にするものだと相場が決まっている。
 ところが、

 ・何度も同じ入力をするのが面倒臭い
 ・コマンドの出力結果をメモするのが面倒くさい

 …というような要求が出現することも少なくない。そのような場合の操作について、今回は解説を加えておきたいと思う。

 「標準エラー出力」はちょっと別格として、今は横に置いておく。

 「標準入力」と、「標準出力」は、UNIX/Linuxが標準的に用意している入力経路・出力経路のことを言う。誰にとって「標準的」なのかといえば、それはそれぞれのコマンドから見て標準的な入力、標準的な出力なんだ…ということになる。
 つまり、通常、なにがしかのコマンドが

 「あー。ここで入力して欲しいものがあるんだよなー」

 …と思えば、それは標準入力から入力してもらうようにコマンド(プログラム)を作成しておけば、あとはUNIX/Linuxがうまいこと取りはからってくれる事が約束されている。
 一方で、

 「あー。今ここで出力したい事があるんだよなー」

 …ということになれば、その内容を標準出力に出力するようにコマンド(プログラム)を作成しておけば、あとはUNIX/Linuxが上手いこと取りはからってくれる事が約束されているのである。

 「標準入力」からの入力、あるいは「標準出力」への出力 について、コマンド(プログラム)内部でどのように扱うのかは、それぞれのコマンド(プログラム)が好きに扱って良いことになっている。一方でコマンド(プログラム)の外側での振る舞いは、ユーザーの要望を受けてUNIX/Linuxが適切に取り扱うのであって、コマンド(プログラム)から振る舞いを指定することができない。

 どういうことか?
 例えば、そのサーバの時計を表示するコマンドで試してみる。コマンドプロンプトから、dateとコマンドを入力してみよう。すると…
[piro791@urd stdio]$ date
2012年 11月 15日 木曜日 10:48:04 JST
[piro791@urd stdio]$

 現在の日時が出力される。この結果はdateコマンドの内部で「2012年 11月 15日 木曜日 10:48:04 JST」という文字を「標準出力」に出力するようにプログラミングされているのである。そして、その「標準出力」に出力された内容をUNIX/Linuxが受け取って、画面上に表示していることになる。

 この「標準出力」の出力先を変更する方法がある。これが今回のメインテーマなのだ。

 では、今度はdateコマンドをこのように入力してみてもらいたい。

 date > hiduke.txt

 するとこうなる…
[piro791@urd stdio]$ date > hiduke.txt
[piro791@urd stdio]$

 画面上には何も表示されなくなった。あの日時の表示はどこにいったのか??
 それは、「hiduke.txt」というファイルに出力されたのである。
 lsコマンドで確認してみよう。すると…
[piro791@urd stdio]$ ls -la
合計 12
drwxrwxr-x 2 piro791 piro791 4096 11月 15 10:53 2012 .
drwx------ 3 piro791 piro791 4096 11月 15 10:19 2012 ..
-rw-rw-r-- 1 piro791 piro791   43 11月 15 10:53 2012 hiduke.txt
[piro791@urd stdio]$

 確かに、「hiduke.txt」というファイルが存在している。このファイルをcatコマンドで覗いてみると
[piro791@urd stdio]$ cat hiduke.txt
2012年 11月 15日 木曜日 10:53:39 JST
[piro791@urd stdio]$

 dateコマンドが出力したであろう結果がファイルの中に書き込まれている。
 このように、「>」記号を使うと、「標準出力」の出力先が画面上から指定されたファイルへと変更されていることがわかる。

 lsコマンドでも試してみよう。今度は

 ls -la /bin > bindir.txt

 としてみる。すると…
[piro791@urd stdio]$ ls -la /bin > bindir.txt
[piro791@urd stdio]$

 lsコマンドの結果は画面上には何も表示されていないが、これは「bindir.txt」というファイルの中に記録されているはずである。
[piro791@urd stdio]$ ls -la
合計 20
drwxrwxr-x 2 piro791 piro791 4096 11月 15 10:59 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 10:53 2012 hiduke.txt
[piro791@urd stdio]$

 「bindir.txt」というファイルが確かに存在している。では、中身を確認してみよう。
[piro791@urd stdio]$ cat bindir.txt
合計 7684
dr-xr-xr-x.  2 root root   4096  9月 17 03:42 2012 .
dr-xr-xr-x. 22 root root   4096 11月 11 04:22 2012 ..
-rwxr-xr-x.  1 root root    123 11月 24 23:50 2010 alsaunmute
-rwxr-xr-x   1 root root  27808  3月 26 07:03 2011 arch
lrwxrwxrwx.  1 root root      4 12月 17 13:19 2011 awk -> gawk
-rwxr-xr-x   1 root root  26264  3月 26 07:03 2011 basename
-rwxr-xr-x   1 root root 938672  5月 27 00:46 2011 bash
-rwxr-xr-x   1 root root  51344  3月 26 07:03 2011 cat

 (※途中省略※)

-rwxr-xr-x   1 root root 772040  2月 26 00:33 2011 vi
lrwxrwxrwx.  1 root root      2 12月 17 13:19 2011 view -> vi
lrwxrwxrwx.  1 root root      8 12月 17 13:19 2011 ypdomainname -> hostname
-rwxr-xr-x.  1 root root     62 11月 23 16:26 2010 zcat
[piro791@urd stdio]$

 …と、なっている。なお、「ls -la /bin」とだけ実行してみると、これと全く同じ結果になることが判ると思う。

 このように、「>」記号を使うことで、標準出力の出力先を画面上からファイルに変更することが可能になるのだった。

 次に、「標準入力」をキーボードからの入力ではなく、ファイルからの入力に変更してみる。
 こちらは、標準出力の「逆向きの記号」つまり…

 <

 を使う。
 まだ説明はしていないが、ここでは「wcコマンド」(トイレではない)を使ってみることにする。

 まず、「wc -l」と、コマンドを入力してみよう。すると…
[piro791@urd stdio]$ wc -l

 と、プロンプトが表示されず、コマンドを入力した次の行でカーソルが止まっている様子がわかるだろう。
 実はコレ、wcコマンドが標準入力からの入力を待ち構えているのである。

 ではここで、「abcdefg(Enterキー)」と3回ほど繰り返してみる。するとこうなる。
[piro791@urd stdio]$ wc -l
abcdefg
abcdefg
abcdefg

 入力したとおりに3行表示されている。
 ここで、「Ctrl+D」(Ctrlキーを押しながらDキー)を押してみよう。すると…
[piro791@urd stdio]$ wc -l
abcdefg
abcdefg
abcdefg
3
[piro791@urd stdio]$

 と、「3」と新たに表示された後に、コマンドプロンプトが返ってきた。

 wcコマンドとは、「文字数(バイト数)」「単語数」「行数」などを数えてくれるコマンドで、今回は「-l」というオプションを付けているので、「行数を数えている」のである。「abcdefg」と入力して「Enter」キーを押しているので、入力した行数は3行。だから「3」という結果が標準出力に出力されているのだ。
 ほとんどの場合、キーボードから入力してwcコマンドで数えさせるなんてことはしない。普通やらない。というか、そんなのはこういうサンプル以外では見たことが無い。(笑)

 よくある使い方としては…
[piro791@urd stdio]$ ls -la
合計 20
drwxrwxr-x 2 piro791 piro791 4096 11月 15 10:59 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 10:53 2012 hiduke.txt
[piro791@urd stdio]$ wc -l bindir.txt
109 bindir.txt
[piro791@urd stdio]$

 このように、wcコマンドでファイル名を指定して、そのファイルの行数を数える…的な使い方が一般的ではある。しかし、場合によっては標準出力からファイルの内容を与えて行数を数えさせる事もありうるのであった。
[piro791@urd stdio]$ wc -l < bindir.txt
109


 wc -l < bindir.txt

 ファイル「bindir.txt」の中身を標準入力としてwcコマンドに与えている。この時、wcコマンドとしてはその内容がキーボードから入力されたのと同じ振る舞いをすることになる。wcコマンドには、その入力内容がキーボードから入力されたのか、ファイルから入力されたのかは判らないし、そもそも気にすることもない。

 この「標準入力」の使いどころとしては、「入力する内容が物凄く沢山あってキーボードから入力とかあり得ない」とか、「毎回毎回同じ事を入力するのは本当に面倒臭い」とか、「絶対にミスできない入力を事前に用意しておいて、再三チェックしてから入力したい」とか、そんな場合で大活躍するはずだ。

 続いて、別格扱いをした「標準エラー出力」について説明する。

 先ほどの例で、「bindir.txt」の行数を数えるwcコマンドの例で、「wc -l bindir.txt」という形式でコマンドを実行していた部分を再度思い出して欲しい。
[piro791@urd stdio]$ wc -l bindir.txt
109 bindir.txt
[piro791@urd stdio]$

 ファイルbindir.txtは109行あるということが判る。この出力結果を画面上ではなく「wckekka.txt」というファイルに保存するとしよう。復習になるが、こんな感じでよいはずだ。

 wc -l bindir.txt > wckekka.txt

 試してみよう。
[piro791@urd stdio]$ wc -l bindir.txt > wckekka.txt
[piro791@urd stdio]$ cat wckekka.txt
109 bindir.txt
[piro791@urd stdio]$

 wcコマンドは無言で終了し、ファイル「wckekka.txt」にはwcコマンドで表示された内容が記録されている。
 次に、wcコマンドで指定したファイル「bindir.txt」のファイル名をわざと間違えてみることにする。するとどうなるだろうか…
[piro791@urd stdio]$ wc -l bakaahomanuke.txt > wckekka2.txt
wc: bakaahomanuke.txt: そのようなファイルやディレクトリはありません
[piro791@urd stdio]$

 「bakaahomanuke.txt」というファイルは存在しないので、wcコマンドとしては何を数えたら良いのかさっぱりわからない。よって、「そんなファイルはねーよ!」というたぐいのエラーメッセージを出力している。
 ところが、標準出力は「wckekka2.txt」というファイルに記録するように、出力先を変更しているにもかかわらず、画面上に『wc: bakaahomanuke.txt: そのようなファイルやディレクトリはありません』などと出力されているではないか。
 この時、wckekka2.txtはどうなっているのかというと…
[piro791@urd stdio]$ ls -la wckekka2.txt
-rw-rw-r-- 1 piro791 piro791 0 11月 15 12:59 2012 wckekka2.txt
[piro791@urd stdio]$

 なんと、ファイルが作成されている。
 ファイルの大きさは「0バイト」…つまりからっぽということになっている。これは、wcコマンドが実行はされた物の\指定されたファイルが正しくなかったので何も出力しないで終了したということになる。

 そう…つまり、「そのようなファイルやディレクトリは…」というエラーメッセージは標準出力に出力された物ではないのである。

 このようなエラーメッセージは、そのまま標準出力に出力されてしまうと、コマンドを実行しようとしている人に見落とされてしまうリスクがある。そこで、標準出力とは別の経路を用意しておき、オペレーターに警告を伝える必要がある。その「別の経路」こそが、

 標準エラー出力

 なのである。
 ところが、

 ・エラーが出ても無視したい

 とか、

 ・エラーメッセージこそ、ファイルに記録しておきたい

 …というケースもゼロではないので、これも出力先を変更する方法が存在する。そのために用いる記号が、

 2>

 である。数字の「2」が付いている点が重要なポイント。実際の使い方として、wcコマンドのエラーメッセージをファイルに保存する方法で例示するとこうなる。

 wc -l bakaahomanuke.txt 2> wcerror.txt

 確認してみよう。
[piro791@urd stdio]$ wc -l bakaahomanuke.txt 2> wcerror.txt
[piro791@urd stdio]$ cat wcerror.txt
wc: bakaahomanuke.txt: そのようなファイルやディレクトリはありません

 wcコマンド自体は無言で終了していることが判る。本来ならエラーメッセージが出力されたはずだ。しかし今回は「標準エラー出力」の出力先をファイルに変更しているので、その結果は「wcerror.txt」というファイルに記録されることとなる。
 catコマンドで内容を確認すると、確かにエラーメッセージが記録されていることが判る。

 なお、標準出力と、標準エラー出力とを同時に変更することも出来る。
 例えば、wcコマンドの出力結果について、

 ・実行結果を「wckekka.txt」に記録する
 ・エラーメッセージを「wcerror.txt」に記録する

 ということも可能だ。入力すべきコマンドは次のようになる。

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

 要するに、「>」と「2>」とを単純に並べて書いたらOKなのだ。
 それでは試してみよう。
[piro791@urd stdio]$ wc -l bindir.txt > wckekka.txt 2> wcerror.txt
[piro791@urd stdio]$ cat wckekka.txt
109 bindir.txt
[piro791@urd stdio]$ cat wcerror.txt
[piro791@urd stdio]$

 今回のwcコマンドは特にエラー等起こすこと無く実行が完了しているので、「wckekka.txt」の中にその実行結果が記録され、「wcerror.txt」は空っぽ(catコマンドで何も表示されない)になっていることが判る。

 ちなみに、「>」とか、「2>」とかで出力先を変更することを、「出力リダイレクト」といい、「<」で入力元を変更することを「入力リダイレクト」といいます。

 次回のアーティクルでは、「出力リダイレクト」についてありがちな問題について解説したいと思います。
nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

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

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

トラックバック 0

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