いづいづブログ

アジャイルコーチになりたい札幌在住SEです。アジャイル札幌スタッフ&ScrumFestSapporo実行委員。Like:パクチー/激辛/牡蠣/猫/初期仏教

標準入出力・リダイレクション・パイプ

Linuxのキモである「標準入出力・リダイレクション・パイプ」について調べた。

標準入出力

標準入力、標準出力についてはここから引用*1

標準入力 【 standard input 】 stdin

 標準入力とは、コンピュータ上で実行されているプログラムが、特に何も指定されていない場合に標準的に利用するデータ入力元。コンピュータの入力装置やOSが提供するデータ入力機能・経路などを指し、多くのシステムではキーボード装置による利用者の文字入力が標準入力に設定されている。システム上では “stdin” の略号で表されることが多い。


標準出力 【 standard output 】 stdout

 標準出力とは、コンピュータ上で実行されているプログラムが、特に何も指定されていない場合に標準的に利用するデータ出力先。コンピュータの出力装置やOSが提供するデータ出力機能・経路などを指し、多くのシステムではディスプレイ装置による利用者への文字表示が標準出力に設定されている。システム上では “stdout” の略号で表されることが多い。


標準エラー出力 【 standard error 】 stderr

 基本的に標準出力と同じだが、エラーメッセージや診断メッセージの出力に特化したデータ出力先。標準出力とは独立しているため通常の出力結果はファイルに出力して、エラーメッセージはディスプレイに表示させるということが可能。


つまりまとめると…
標準入出力とは、デフォルト(=特に何も変更しなかった場合)で標準として利用するデータの入力元、出力先のこと。

標準入力、標準出力、標準エラー出力の3つに分類され、多くのシステムでの標準入力はキーボード、標準出力と標準エラー出力はディスプレイとなっている。

Linuxでは標準入出力を以下の番号で識別している。

入出力 番号 装置
標準入力 キーボード
標準出力 ディスプレイ
標準エラー出力 ディスプレイ


f:id:izumii-19:20181129123633p:plain:w600
標準入出力

実行結果

キーボード(=標準入力)から「echo hello world」と入力すると、ディスプレイ(=標準出力)に「hello world」と出力される。

$ echo hello world
hello world

リダイレクト

リダイレクトは標準入力、標準出力、 標準エラー出力を切替える機能のことで、リダイレクションとも呼ばれる。

通常はキーボード(=標準入力)から入力したコマンドが実行された結果をディスプレイ(=標準出力)に出力するが、リダイレクションすることで

  • キーボード(=標準入力)から入力したコマンドが実行された結果を、ファイル(=標準出力)に保存する
  • ファイル(=標準入力)から読み込んだデータを、別なファイル(=標準出力)に保存する

というようなことができるようになる。

f:id:izumii-19:20181129123708p:plain:w600
リダイレクト

1) コマンド > file

コマンドの標準出力をfileに書き込む。既存データが存在する場合は上書きされる。

以下はキーボードから「Hello World」と入力した結果をHello.txtというファイルに出力している。

$ echo Hello World >Hello.txt
$ cat Hello.txt
Hello World

2) コマンド >> file

コマンドの標準出力をfileに追加する。「>」は「1>」の省略形。1は標準出力の番号。

以下は1)を実行した後に、キーボードから「Close World」と入力した結果をHello.txtというファイルに出力(追加)している。

$ echo Close World >> Hello.txt
$ cat Hello.txt
Hello World
Close World

3) コマンド < file

コマンドはfileの内容を標準入力として受け取る。「<」は「0<」の省略形。0は標準入力の番号。

以下は2)を実行した後に、Hello.txtの中身を「Hello」でgrepした結果をディスプレイに出力している。

$ grep Hello < Hello.txt
Hello World

4) コマンド 2> file

コマンドの標準エラー出力をfileに書き込む。
エラーが発生しない場合は、出力先のファイルには空のデータが書き込まれるため、結果として空ファイルが作られる。

◯エラーが発生する場合の例

aaaファイルは存在しないのでerr.txtにエラーが出力される

$ ls aaa 2> err.txt
$ cat err.txt
ls: 'aaa' にアクセスできません: そのようなファイルやディレクトリはありません

◯エラーが発生しない場合の例

aaaファイルを作成してからlsコマンド実行。err.txtは空データで上書きされるためcatで中をみても何もない。

$ touch aaa
$ ls aaa 2> err.txt
aaa
$ cat err.txt
$

5) コマンド > file 2>&1

標準エラー出力の出力先を、標準出力の出力先にマージする。

書き方 説明
1>&2 標準出力を、標準エラー出力にマージする
2>&1 標準エラー出力を、標準出力にマージする


以下は「 aiueo」と書かれているaaaファイルと、存在しないbbbの中身を、catで表示しようとしている例。cat aaaの実行結果とcat bbbの実行結果(この場合はファイルが存在しないエラー)が一緒にresult.txtに出力される。

$ echo aiueo >aaa
$ cat aaa bbb >result.txt 2>&1
$ cat result.txt
aiueo
cat: bbb: そのようなファイルやディレクトリはありません

パイプ

コマンドの 出力を、直接他のコマンドの入力にすることできる機能。

例えば、ファイル(aaa,bbb,ccc)を降順に並び替えてディスプレイに表示したい場合、

  1. lsコマンドの実行結果をlist.txtに出力
  2. list.txtの中身をSortの降順に並び替えた結果をsort.txtに出力

というように中間ファイルを介して処理を行うことになり、コードが増えたり中間ファイルを削除する処理が増える。

$ ls >list.txt
$ sort -r list.txt > sort.txt
$ cat sort.txt
sort.txt
list.txt
ccc
bbb
aaa

f:id:izumii-19:20181129124249p:plain
パイプを使わない例

これをパイプを利用して、「lsコマンドの出力結果」を次の「Sortコマンドの入力」にすると以下のように1行で書くことができ中間ファイルも必要ない。

$ ls | sort -r
ccc
bbb
aaa

f:id:izumii-19:20181129123755p:plain
パイプを使う例

書き方の例は以下の通り。

1) command1 | command2

command1の標準出力をcommand2の標準入力にわたす。command1の標準エラー出力はcommand2にはわたらない。

2) command1 |& command2

command1の標準出力と標準エラー出力をcommand2の標準入力にわたす。

3) パイプは何個でも続けることができる

command1 | command2 | command3 | ...

スペシャルファイル

スペシャルファイルとは、ファイルシステム上であたかも通常のファイルのような形で提示されるデバイスドライバのこと。

この中でもリダイレクトによく使われる「/dev/null」は、スペシャルファイルのうち「擬似デバイス」に分類され、実際の周辺機器ではない架空のデバイスである。

/dev/null

そこに書き込まれたデータを全て捨て、読み出しても何も返さない仮想デバイス

よくブラックホールとかゴミ箱と表現されている。 なので、必要のないデータを捨てたい時に「/dev/null」にリダイレクトするという使い方をすることが多い。

以下を実行すると実行結果を全てゴミ箱に捨てるイメージ。

$ ./test.sh > /dev/null 2>&1

「全部ゴミ箱に捨てたいときは/dev/null 2>&1」ってまる暗記してもいいみたい*2だけど、そもそもの意味を知りたいときはここに詳しく書いてあった。

*1:標準エラー出力については調べて書きました。

*2:逆(1>&2)はだめらしい。https://qiita.com/ryskiwt/items/d4e7846fd47364a2a4e2