標準入出力・ファイル・リダイレクト・パイプについて
はじめに
この記事は私の知識の整理のために、標準入出力・ファイル・リダイレクション・パイプについてまとめたものです。 webアプリの開発をするときにはそこまで意識しないことではありますが、開発者としては抑えておくべき基礎なので、それを自分なりに、他人に説明するくらいのスタンスでまとめてみました。 間違いなどあればご指摘ください!それでは書いていきます。
標準入力
これは、コンピューター上で実行されているプログラムが、何も特別な指定がされていない場合に利用するデータの入力元のことを言います。 少し分かりにくいと思うので、コマンドラインを例にとると
$ ls
とすると、結果が返ってきますよね。この ls
が標準入力です。
標準出力
先ほどの標準入力(ls)を入力してEnterキーを押すと
Applications Creative Cloud Files Desktop Documents Downloads
みたいな感じでその結果が返ってきます。これが、標準出力です。 標準出力は、標準入力がプログラムに渡り、そこから出力される結果ということですね。
10 + 1 = 11 みたいな式があるとしたら、 10と1が標準入力、 10 + 1という演算がプログラム、 11が標準出力 といった具合です。
標準エラー出力
主にプログラムのエラーを表示するために使用されます。
ls
コマンドで存在しないファイルを指定した場合、下記のようなエラーメッセージが表示されます。このエラーメッセージは標準エラー出力に表示されています。
$ ls /aaaaaa ls: /aaaaaa: No such file or directory
ファイル
コンピューター上で管理される情報の単位のこと。ファイルの名前は人間が識別しやすいように名前がつけられています。sample.txt
や hoge.html
のようなものがそれに当たります。
ファイルはそれ単体でもコンピューター上に存在するが、XX関連のファイルをまとめておきたい、という場合にフォルダという単位でファイルを格納することもできます。
また、ファイルは主に、プログラムファイル、データファイルに分かれます。
プログラムファイルはJavascriptやRubyなどで書かれたファイル(例えば sample.js
sample2.rb
など)を指し、データファイルはpngやjpgの画像ファイルなど、それ自体はコンピューター上で実行されず、プログラムによって読み込みまれるようなものを指します。
フォルダも管理する上での単位という意味ではファイルと同じですが、フォルダは「フォルダの中にファイルを入れることができ、かつ、フォルダも入れることができる」というのが1つの特徴です。
テキストファイル・バイナリファイルという分類もあり、テキストファイルは人間が識別できる文字や数字で書かれたファイルのことで、バイナリファイルは人間では読めない形式(コンピューターが読む前提の形式)でのファイルのことになります。
リダイレクト
標準入力、標準出力先を変更する機能のこと。
例えば cat
コマンドは
$ cat file_name
のようにしてfileの中身を表示しますが、その出力先を変えたり、標準入力の元ファイルを変更したりするのに使うことができます。
リダイレクトは主に >
と <
を使用して入出力をコントロールします。
例えば、ls -l
コマンドで表示できる内容を、コマンドライン上に出力するのではなく、result.txt
に送りたい、という場合は
ls -l list.txt
とします。これで、ls -l
の結果が result.txt
に全て入るようになります。書き込まれたかどうか確認するには
cat result.txt
で確認できます。
ただし、標準エラー出力は
$ ls /aaaaaa > list.txt ls: /aaaaaa: No such file or directory
のように単純にリダイレクトしても、コマンド上に表示されてしまうので
$ ls /aaaaaa 2> list.txt
のように 2>
をリダイレクトに使うことでファイル内に格納します。
また、「コマンドの結果とエラーメッセージを別々のファイルに出力したい」というケースもあるかと思いますが、その場合は
$ ls /aaaaaa > list.txt 2> error.txt
のようにします。これは、実行結果は list.txt
へ、エラーは error.txt
へと送られるコマンドです。1行で書けて便利ですね!
コマンドの結果とエラーメッセージを合わせて1つのログファイルにしたい!というときは
$ ls / aaaaaa > result.txt 2>&1
のようにすることで、1つのファイルにまとめて出力できるようになります。
コマンドの意味合いとしては、最初の >
が標準出力先を result.txt
に設定するためのコマンド、次の 2>
が標準エラー出力の設定先を設定するためのコマンド、最後の &1
が標準出力と同じファイルへ出力先を指定するためのコマンド、といった具合です。2>&1
で1つのセットとしても良いかもしれません。これも便利です。
リダイレクトをすると、指定したファイル名と同じファイル名がある場合には、特別な設定を何もしなければ、その内容が上書きされてしまいます。
$ echo 10000 > number.txt
$ echo 99999 > number.txt
として、catで内容を表示すると
$ cat number.txt 99999
となり、元の10000は上書きされてしまいます。
上書きを防ぐには >>
を使って、ファイルの末尾に追加する、というような処理を使います。
また、シェルのオプションで noclobber
というオプションを使うとファイルの上書きの禁止ができるので、それを設定して上書きをさせない設定にするというのも1つの手段です。
パイプ
コマンドは1つ入力して出力させておしまいではありません。複数コマンドをつなげて、より複雑なこともできます。例えば、/binフォルダの中にあるファイルの、ファイルサイズが大きい順の3つを取得する、というようなこともできたりします。
それを実現するために必要なのが、パイプという機能です。
まずは例を見てみましょう。
$ ls -l / > sample_list.txt $ less sample_list.txt
これでも結果を表示することはできますが、1行で書く方法でパイプを使用します。
$ ls -l | less
この例を見れば想像がつくかもしれませんが、パイプ(記号で表すと |
)によって、前のコマンドの結果を次のコマンドに渡すことができるということです。実行結果を渡せるのは便利ですね。
このパイプを、フィルタと呼ばれる標準出力を入力として受け取り、標準出力に出力するコマンドと一緒に使うことで、/binフォルダの中にあるファイルの、ファイルサイズが大きい順の3つを取得する、ということを実際に書いてみます。
使うコマンドは3つで、 du、sort、head のみです。
- duコマンド→-kオプションを渡すことで、ファイルのサイズをキロバイト数で表示する
- sortコマンド→昇順(今回は小さい順)に並べる。デフォルトはアルファベット順だが、-nオプションをつけることでサイズ順に並べることができる。-rオプションをつけると逆順になる
- headコマンド→上から順に取得した結果を表示する -n 3のようにオプションを渡すと上から3つを取得できる
という特徴を使ってコマンドを書くと
$ du -k /bin/* | sort -n -r | head -n 5
となり、出力結果は
720 /bin/ksh 368 /bin/zsh 340 /bin/bash 260 /bin/tcsh 260 /bin/csh
となります。キロバイト数の大きい順に表示され、やりたいことも達成できました。
コマンドラインはあまりちゃんと勉強してこなかったので、勉強すると基礎でも奥が深いなと感じました。