はじめに
Linux では、キーボードから入力されたデータ、ファイルを読み込むことで取得したデータを ストリーム として扱う。
また プロセス には、
- ストリームを生成することができるプロセス
- ストリームを引数に受け取るプロセス
ストリームを生成することができるものにはプロセスの他に、
- 端末(キーボード)
- ファイル
- 別のプロセス
がある。また、ストリームを受け取ることができるものには
- 端末(ディスプレイ)
- ファイル
- 別のプロセス
がある。
生成されたストリームが上記のいずれかに流れるようにすることを 接続する と表現する。
「端末 」には文脈次第で色々な意味が含まれるが、ここのでの端末は TTY(実際の端末) や PTY(擬似端末) を指す。
通常、プロセスや端末などは明示的に接続元や接続先を指定しなくても良い。デフォルトで繋がっている接続が存在するためである。
このストリームのデフォルトの接続元を 標準入力、接続先を 標準出力 と呼ぶ。
これら標準入出力はリダイレクト演算子によって リダイレクト することができる。これによって、コマンド同士を連携させ、様々なスクリプトが実現される。
リダイレクト演算子は、標準入出力を変更することができる
標準入力 / stdin
Standard Input
プログラムがデータ(ストリーム)の入力を必要とする際、明示的に入力元ストリームを指定しなかった場合に使用される、標準のデータ入力元ストリーム。
ファイルディスクリプタは 0
。
通常、多くのプロセスの標準入力は キーボード(/dev/tty
)に接続されている。
標準出力 / stdout
Standard Output
プログラムが実行結果のデータ出力を行う際に、明示的に出力先ストリームを指定しない場合に標準で使用される、データの出力先ストリーム。
ファイルディスクリプタは 1
。
多くのプロセスは通常、標準出力が 端末 に接続されている。
$ echo
や $ printf
の実行結果は標準出力に流れている。
標準エラー出力 / stderr
Standard Error
エラーメッセージや警告メッセージの出力先となるストリーム。
ファイルディスクリプタは 2
。
通常、多くのプロセスの標準エラー出力は 端末 に接続されている。
ファイルディスクリプタ
File Descriptor
リソースを識別するための識別子。
リソースへアクセスするためのインターフェースとしてカーネルから提供される。
「リソース」とは下記のようなものを指す。
- ファイル
- 標準入出力
- パイプ
- プロセス間でデータをやり取りするための特殊なリソース
- ファイルディスクリプタを使って実装されている
- ソケット
ファイルディスクリプタはリソースの識別子であるものの、全てのリソースに対して存在するわけではなく、プロセスがリソースをオープンした時に初めてそのプロセスに対して割り振られる。
具体的には、プロセスが システムコール の open()
や socket()
によって新たにファイルやデバイスを開くときに、戻り値としてファイルディスクリプタが返却され、これがそのプロセスに対して割り当てられる。その後の read()
や write()
などのリソースとのやり取りはこのファイルディスクリプタを使って行われる。
プロセスは下記のようなテーブルを プロセスごとに保持 していて、ファイル、ソケット、パイプなどのリソースへアクセスを行う。
標準入出力に対しては、あらかじめ 0
、1
、2
の固定値が割り当てられている。
ファイルディスクリプタ | リソース | デフォルトの接続先 |
---|---|---|
0 |
標準入力 | キーボード(/dev/tty ) |
1 |
標準出力 | 端末(/dev/tty ) |
2 |
標準エラー出力 | 端末(/dev/tty ) |
3 以降 |
プロセスがオープンしたファイル・ソケット・パイプなど | - |
各プロセスに関連するファイルディスクリプタは、/proc/プロセスID/fd/
ディレクトリに として格納され、 として表示される。
/proc/PID/fd/
内には、プロセスが開いているファイルディスクリプタが 仮想ファイル への シンボリックリンクとして存在する。
例えば、
0 -> /dev/tty1
なら、標準入力(0
)が tty1
に接続されていることを示す。
$ ls -l /proc/$$/fd
lrwx------ 1 user user 64 Feb 15 12:34 0 -> /dev/tty1
lrwx------ 1 user user 64 Feb 15 12:34 1 -> /dev/tty1
lrwx------ 1 user user 64 Feb 15 12:34 2 -> /dev/tty1
lr-x------ 1 user user 64 Feb 15 12:34 255 -> /dev/tty1
※ $$
は ビルトインシェル変数 としても利用される表現で、現在実行中のプロセスを表す。
※ /proc/
ディレクトリについては こちら。
$ ls -l /proc/12345/fd # PID が 12345 のファイルディスクリプタを確認
$ tty
teletypewriter = tele(遠隔地の)タイプライター
現在の環境のシェルの
- 標準入力
- 標準出力
- 標準エラー出力
が接続されたデバイスファイルを表示するコマンド。
$ tty
出力される /dev/ttys000
や /dev/ttys001
など tty
で始まるものは一般に、ローカル環境の端末を表し、pts
で始まるものは SSH や Telnet などを経由してネットワーク越しに接続された端末を表す。
(端末については こちら)
パイプ / |
Pipeline
コマンド同士を |
で連結することにより、コマンドの実行結果を、別のコマンドが必要とする引数として渡すことができる。
内部的には1つ目のコマンドの標準出力が2つ目のコマンドの標準入力に接続されている。
$ コマンド1 | コマンド2
$ ls | grep ".txt"
リダイレクト
リダイレクト演算子を使用して標準入力や標準出力を変更すること。
ファイルディスクリプタ を組み合わせて使用するものがある。
>
標準出力を、演算子の右側で指定したファイルに変更することができる。
ファイルが存在することが前提で、出力結果は上書きされる。
実行結果を標準出力へ出力するコマンド(echo
、printf
、pwd
、date
、...)に対して使用することができる。
$ コマンド > ファイル名
ファイルディスクリプタを指定すると、標準エラー出力をファイルに変更することができる。
$ コマンド 2> ファイル名
&
を使うことで、標準出力と標準エラー出力を同じ先にリダイレクトできる。
$ コマンド &> ファイル名
$ コマンド >& ファイル名
>>
標準出力を、演算子の右側で指定したファイルに変更することができる。
ファイルが存在することが前提で、出力結果は末尾に追記される。
$ コマンド >> ファイル名
ファイルディスクリプタを指定すると、標準エラー出力をファイルに変更することができる。
$ コマンド 2>> ファイル名
<
標準入力を、演算子の左側で指定したファイルに変更することができる。
標準入力を使用するコマンド(cat
、grep
、sort
、uniq
、wc
、cut
、tee
、head
、tail
)に対して使用することができる。
$ コマンド < ファイル名
<<
ヒアドキュメント(Here Document)を標準入力とするための機能。
<<
で指定した任意の文字列を「ヒアドキュメント開始」、「ヒアドキュメントの終了」の合図とすることができる。
文字列には End of File の頭文字をとった EOF
がよく使用される。
$ コマンド << EOF
# ヒアドキュメントとなる部分
# ヒアドキュメントとなる部分
# ヒアドキュメントとなる部分
EOF
$ コマンド << AAA
# ヒアドキュメントとなる部分
# ヒアドキュメントとなる部分
# ヒアドキュメントとなる部分
AAA
<<
はシェルに対して「次に続く文字列(EOF
)が現れるまでを標準入力として扱う」という指示を与えている。
またヒアドキュメント内では、変数展開 や コマンド置換 を使用することができる。
2>&1
標準エラー出力を標準出力に結合する。
>
を併せて利用することで、標準出力と標準エラー出力の両方を同じ場所にリダイレクトさせることができる。
$ コマンド > ファイル名 2>&1
2>&1
が末尾につく理由
2>&1
はあくまでも「標準エラー出力」を「現在の標準出力」に合わせる効果しかない。
$ コマンド > ファイル名 2>&1
上記では、 $ コマンド > ファイル名
によって標準出力が指定したファイルに変更された後に、標準エラー出力を標準出力先に統一している。
誤って、
$ コマンド 2>&1 ファイル名
とした場合、そもそも標準出力先を変更していないので、何も変化がない。
また、
$ コマンド 2>&1 > ファイル名
とした場合も、エラー標準出力が変更されるタイミング($ コマンド 2>&1
)の標準出力は、まだリダイレクトによって変更されていないので、$ コマンド 2>&1
が何も効果を持たない。
/dev/null
特殊な デバイスファイル。
/dev/null
に送られたデータは、即座に消去され、どこにも保存されない。
保存されないため、ストリームに容量制限がなく、ストレージを占有することがない。
$ cat
concatenate
ファイルの内容を標準出力へ出力する。
$ cat ファイル名
$ cat -n ファイル名 # 行番号も表示する
$ xargs
標準入力から受け取った文字列を、別のコマンドの引数に渡しながら実行する。
パイプ と併せて利用される。
$ コマンド | xargs 実行したいコマンド # 実行したいコマンドには、先頭のコマンド実行結果が標準入力として渡る
-n
オプションを指定すると、引数を指定した数ずつ分割して渡すことができる。
$ echo "arg1 arg2 arg3" | xargs -n 1 echo
$ tee
標準入力から受け取ったストリームを、標準出力とファイルの両方へ出力する。
コマンドの実行結果をファイルに書き込みしながら、次のコマンドへと渡すことができる。
パイプ と併せて利用される。
$ コマンド | tee ファイル名 | コマンド # 最後のコマンドには、最初のコマンドの実行結果が標準入力として渡る
$ dd
Data Duplicator(俗称)
Data Definition(正式)
入力ファイルからデータをブロック単位で読み取り、ファイルまたは標準出力へ送信する。
ファイルシステムの構造やデバイスのブロック単位でコピーできるため、ディスクのバックアップやデータの変換に利用される。
$ cp
よりも、より低レベルなデータ操作が可能。
if
= input file
of
= output file
if
、of
にはファイルだけでなくデバイス (/dev/sda
など) を指定することも可能なため、ハードディスクや仮想デバイスの操作にも使用される。
$ dd if=入力ファイル of=出力ファイル
$ read
標準入力からデータを読み取り、変数に格納する。
$ read 格納先変数名
変数を指定しない場合、デフォルトでは ビルトインシェル変数 の $REPLY
に格納される。
$ read
HELLO
$ echo $REPLY
HELLO
$ read -t 秒数 格納先変数名