【Linux】標準入出力

Linuxには多くのコマンドが用意されています。一つ一つのコマンドはできるだけ小さく、シンプルな動作をするように設計されています。

これは、コマンドにたくさん積めることより、一つのコマンドには一つの機能を提供することで、単純にした方が明快で使いやすくするためです。

Linuxで様々な処理を行うために、これらの小さなコマンドを連携させる仕組みがリダイレクトとパイプラインはコマンドをうまく組み合わせて連携させるための仕組みです。

スポンサードサーチ

標準有力、標準出力、標準エラー出力

コマンドを連携するやり方を学ぶ前に、まずはコマンド間で情報をやり取りする仕組みを理解する必要があります。そのために予備知識として、標準入出力という言葉について、解説します。

Linuxではcatコマンドが起動されると、自動的に標準的な入出力チャネルが開かれます。チャネルとは日本語では「水路」、「経路」ですがここではデータの流れる道ととらえましょう

 

標準的な入出力チャネルとは下記の三つです

  1. 標準入力(stdin)
    プログラムの入力。通常はkeyboard
  2. 標準出力(stdout)
    プログラムの出力。通常は端末ディスプレイ
  3. 標準エラー出力(stderr)
    プログラムのエラーメッセージを出力するための標準的な出力。通常は、端末ディスプレイが使用される

これの三つを組み合わせて標準入出力と呼びます。

なお、標準入出力をどこに接続するかはシェルで制御できます。Linuxはコマンドの入出力先を標準入出力という形で抽象化しているので、コマンド内部の動作を変更せずにフレキシブルな設定を可能としています。

スポンサードサーチ

リダイレクト

標準入出力先を変更する機能をリダイレクトと呼びます。入力・出力共にリダイレクト可能ですので、そのやり方を解説します。

標準入出力のリダイレクト

catコマンドを見てみましょう。

~user@computer$ cat
Hello #キーボードからHelloと入力
Hello #Helloと表示
$ctrl+dを入力
~$#プロンプトに戻る

これはcatコマンドが、

標準入力の内容を入力として読み込んで、それを標準出力にそのまま出力する

という動きをするコマンドのためです。標準入力は通常はキーボードーであるため、今はキーボードの入力がそのまま表示されていました。

では、キーボードの代わりにファイルを標準入力に繋いでみましょう。これを入力ダイレクトと呼びます。入力リダイレクトは<を使います。次の例では、標準入力がつながっている先を、キーボードから/etc/crontabファイルに変更しています。

これにより、/etc/crontabファイルの内容が、標準入力としてcatコマンドに渡されます。catコマンドはこれを標準出力にそのまま出力します。結果として、次のように/etc/crontabファイルの内容が表示されます。

~user@computer$ cat
/etc/crontab
# /etc/crontab: system-wide crontab # Unlike any other crontab you don’t have to run the `crontab’
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields, # that none of the other crontabs do. SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .—————- minute (0 – 59)
# | .————- hour (0 – 23)
# | | .———- day of month (1 – 31)
# | | | .——- month (1 – 12) OR jan,feb,mar,apr …
# | | | | .—- day of week (0 – 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed 17 * * * * root cd / && run-parts –report /etc/cron.hourly 25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts –report /etc/cron.daily ) 47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts –report /etc/cron.weekly ) 52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts –report /etc/cron.monthly ) #

入力リダイレクトとファイル指定

catコマンドはコマンドライン引数にファイル指定するとそのファイルの内容を表示するため、入力ダイレクトで書いてもファイル指定で書いても同じ動作となります。

cat < /etc/crontab #入力リダイレクトの書き方
cat /etc/crontab #ファイル指定での書き方

この二つは得られる結果は同じですが、内部の動きは大きく異なります。

入力リダイレクト cat <

「標準入力をそのまま標準出力に表示する」というcatコマンド本来の動きを行っています。

ファイル指定をした方 cat ファイル名

catコマンドが利便性のために用意している「ファイル名が指定された場合にはその内容を対象とする」という動作を利用しています。

これから、Linuxで何かしらのコマンドを作る際には、他のLinuxコマンドと同様に「ファイル指定する」よりも「標準入力から受けるとる」仕組みでプログラムを書くようにしましょう。その方が、汎用性が高く、他のプログラムとの連携もしやすくなります。

標準出力(stdout)のリダイレクト

標準出力もリダイレクト機能により変更可能です。よく使われるケースとして、コマンドの実行結果を画面に表示する代わりにファイルに保存したい場合です。標準出力をリダイレクトするには、>という記号を使います。

次の例では、lsコマンドの実行結果をlist.txtというファイルに保存します。

~user@computer$ ls -l / > list.txt
~user@computer$ cat list.txt
total 1436
lrwxrwxrwx 1 root root 7 Mar 25 06:40 bin-> usr/bin
drwxr-xr-x 2 root root 4096 Mar 25 06:47 boot
drwxr-xr-x 8 root root 2760 May 15 15:00 dev
drwxr-xr-x 135 root root 12288 May 15 15:07 etc
drwxr-xr-x 3 root root 4096 May 8 13:06 home
-rwxr-xr-x 3 root root 1392928 Apr 14 16:39 init
lrwxrwxrwx 1 root root 7 Mar 25 06:40 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Mar 25 06:40 lib32 -> usr/lib32
lrwxrwxrwx 1 root root 9 Mar 25 06:40 lib64 -> usr/lib64
lrwxrwxrwx 1 root root 10 Mar 25 06:40 libx32 -> usr/libx32
drwx—— 2 root root 16384 Apr 11 2019 lost+found
drwxr-xr-x 2 root root 4096 Mar 25 06:40 media
drwxr-xr-x 5 root root 4096 May 8 13:06 mnt
drwxr-xr-x 3 root root 4096 May 10 19:36 opt
dr-xr-xr-x 247 root root 0 May 15 15:00 proc
drwx—— 3 root root 4096 May 13 17:11 root
drwxr-xr-x 8 root root 160 May 15 15:37 run
lrwxrwxrwx 1 root root 8 Mar 25 06:40 sbin -> usr/sbin
drwxr-xr-x 6 root root 4096 Mar 25 06:42 snap
drwxr-xr-x 2 root root 4096 Mar 25 06:40 srv
dr-xr-xr-x 11 root root 0 May 15 14:59 sys
drwxrwxrwt 11 root root 4096 May 15 15:37 tmp
drwxr-xr-x 14 root root 4096 Mar 25 06:41 usr
drwxr-xr-x 13 root root 4096 Mar 25 06:42 var

なお、リダイレクト先のファイルは自動的に作成されます。そのため、touchコマンドで作成する必要はありません。

標準エラー出力

出力チャネルには先ほど紹介した標準出力に加えて、標準エラー出力というものが存在します。

標準エラー出力は主にプログラムのエラーメッセージを出力するために使用されます。例えば、lsコマンドで存在しないファイルを指定した場合は次のようなエラーメッセージが表示されますが、このエラーメッセージは標準エラー出力に出力されています。

~user@computer$ ls /aiueo
ls: cannot access ‘/aiueo’: No such file or directory
通常、標準エラー出力は標準出力と同じく、端末ディスプレイに接続されています。そのため、このままでは表示されているメッセージは

・標準出力

・標準出力エラー

のどちらかかわかりません。

 

そこで、標準出力をファイルにリダイレクトして、画面に表示させないようにします。

次の例では、標準出力をlist.txtというファイルにリダイレクトします。そのため、結果はlist.txtに書き込まれ、端末には何も表示されないはずです。

~user@computer$ ls /aiueo > list.txt
ls: cannot access ‘/aiueo’: No such file or directory

sしかし、実際には画面にはエラーメッセージが表示されました。これは、標準出力と標準エラー別々のチャネルになっているためです。

標準出力はファイルにリダイレクトしましたが、標準エラー出力は変更していません。この仕組みのおかげで、標準出力をファイルにリダイレクトしたときでも、エラーメッセージは画面に表示されるため見逃さずに済みます。

なお、標準エラー出力もファイルにリダイレクト可能です。標準出力のリダイレクト区別するために、標準エラー出力のリダイレクトは2>という記号を使用します。

次の例では、標準エラー出力の出力先をerror.txtというファイルにリダイレクトしています。コマンド実行時には画面に何も表示されず、エラーメッセージがファイルerror.txtに出力されていることが分かります。

~user@computer$ cat error.txt
ls: cannot access ‘/aiueo’: No such file or directory

このようにコマンドの結果とエラーメッセージは分けておくと何かと便利です。そのために、Linuxではこの二つが用意されているのです。

次の様にリダイレクトを同時に指定することで、標準出力と標準エラー出力をそれぞれ別のファイルにリダイレクトすることもできます。

~user@computer$ ls /aiueo > list_0.txt 2> error_2.txt
~user@computer$ cat list_0.txt #何も表示されない
~$cat error_2.txt
ls: cannot access ‘/aiueo’: No such file or directory

標準出力と標準エラー出力をまとめる

標準出力と標準エラー出力をまとめて、リダイレクトしたい場合は、次のように書きましょう。

~user@computer$ ls /aiueo > result.txt 2>&1
:~user@computer$ cat result.txt
ls: cannot access ‘/aiueo’: No such file or directory

意味としては、

  1. >を用いて、標準出力をresult.txtというファイルにリダイレクトしている
  2. 標準エラー出力を&1と同じものにリダイレクトしている。この&1は標準出力を示している。

といったようになります。

入出力チャネル 数値
標準入力 0
標準出力 1
標準エラー出力 2

上の表の様に、Linuxでは標準入出力が数値として管理されています。

先ほどの例では、標準エラー出力(2)を標準出力(1)と同じファイルへ2>&1と書いてリダイレクト指定したわけです。

このように、標準出力と標準エラー出力をまとめてリダイレクトできるようなると、結果とエラメッセージをあわさせて1つのログファイルに取りたいときに大変便利です。

リダイレクトによる上書き

>で標準出力でリダイレクトする際に指定したファイル名と同一のファイルが存在する場合、上書きされて元のファイルが失われます。

~user@computer$ echo 123 > number.txt
~user@computer$ cat number.txt
123   #123と記述されたnumber.txtを作成
~user@computer$ echo 456 > nubmer.txt #同一のファイル名でリダイレクト
~user@computer$ cat nubmer.txt
456  #上書きされてしまう

そこで上書きが心配な方は>>を使ってみましょう。

~user@computer$ echo 789 >> number.txt
cat number.txt
123
789

他の方法ではシェルのオプションでnoclobberという値をsetコマンドで設定すると、リダイレクトで書き換えてしまうときはエラーにするようにもできます。

~user@computer$ set -o noclobber user@computer$ ls -l > nubmer.txt
~user@computer$ ls -l > number.txt
-bash: number.txt: cannot overwrite existing file
記号 内容
< FILE
標準入力をFILEに変更する
> FILE
標準出力をFILEに変更する
>> FILE
標準出力の出力をFILEの末尾に追記する
2> FILE
標準エラー出力をFILEに変更する
2>> FILE
標準エラー出力の出力をFILEの末尾に追記する
> FILE 2>&1
標準出力と準エラー出力を、共にFILEに変更する

 

dev/null

リダイレクト先としてよく、/dev/nullが使われます。

~user@computer$ ls -l
/dev/null crw-rw-rw- 1 root root 1, 3 May 15 14:59 /dev/null

/dev/nullはスペシャルファイルと呼ばれる特別なファイルで、次のような性質を持ちます。

  1. 入力先として指定しても、何も返さない
  2. 出力先を指定しても、書き込んだデータはどこにも保存されずに消える。

例えば、次のように、標準入力を/dev/nullにリダイレクトにすると、入力が何もない状態になります。結果として何も表示されません。

・標準入力を空っぽにする

cat < /dev/null
#何も表示されない

これはコマンドのテスト等、何かしらの理由で入力をemptyにしたいときに使います

標準出力を/dev/nullにリダイレクトすると、本来はコマンドの結果が画面に表示されるところが何も表示されなくなります。

cat /etc/crontab > /dev/null
#何も表示されない

これは次のように、コマンドの表示結果が大量にある場合、標準エラー出力に表示されるエラーメッセージだけを読みたいときに使用する。

 ls / /xxxxx > /dev/null
ls: cannot access ‘/xxxxx’: No such file or directory

その他にもエラーメッセージを非表示にする。

~user@computer$ ls / /xxxxx 2> /dev/null
/: bin dev home lib lib64 lost+found mnt proc run snap sys usr boot etc init lib32 libx32 media opt root sbin srv tmp var

次のようにすることで、何も表示させないことも可能です。

~user@computer$ ls / /xxxxx> /dev/null 2>&1
#何も表示されない

これは、あらかじめわかっている不要なメッセージを表示するときや、コマンドの実行時間を図る際にメッセージ出力を抑止したいときに利用します。

スポンサードサーチ

まとめ

今回の記事では、リダイレクトについてまとめました。たくさんコマンドがあって覚えるのは大変ですが、普段から使って少しずつ覚えていきましょう。次回はパイプラインについてまとめます!

コメントを残す

メールアドレスが公開されることはありません。