Shellの特殊ファイルとその操作(リダイレクト、パイプ)
LinuxのShellはすべてファイルとして制御する。
成果物
目次
1. 特殊ファイル(スペシャルファイル・デバイスファイル)
標準ストリーム | 概要 |
---|---|
/dev/fd/n |
ファイルディスクリプタ(n は識別番号)。fd、ファイル記述子ともいう。 |
/dev/stdin |
標準入力。/dev/fd/0 |
/dev/stdout |
標準入力。/dev/fd/1 |
/dev/stderr |
標準入力。/dev/fd/2 |
特殊ファイル | 概要 |
---|---|
/dev/null |
ここへリダイレクトすると消える |
/dev/zero |
\0 |
/dev/random |
ランダムな文字列。ブロックあり。 |
/dev/urandom |
ランダムな文字列。ブロックなし。 |
/dev/pts/n |
端末を意味する。n は識別番号。stdout, stderrは端末を指している。 |
これら特殊ファイルの使用例を以下に示す。リダイレクトやパイプを用いる。
2. リダイレクト
LinuxのShellではリダイレクトによって以下の構文を表現する。
5W1H | 値 |
---|---|
何を | ファイルA |
どこへ | ファイルB |
どうする | (出力|入力) |
2-1. 標準ストリーム
echo
は引数の文字列を標準出力(stdout)へ出力するコマンドである。
echo 'A'
これを標準エラー出力(stderr)へ出力させるには以下のようにリダイレクトする。
echo 'A' 1>&2
stdoutのファイルディスクリプタ1
は省略できる。
echo 'A' >&2
端末にはstdoutとstderrの両方が出力される。よって片方を出力しても違いが確認できない。そこで両方を別々に出力させてみる。
{ echo 'Out'; echo 'Err' >&2; } 1>out.txt 2>err.txt
以下で確認する。stdoutはout.txt
に、stderrはerr.txt
に出力されている。
$ cat out.txt Out $ cat err.txt Err
以下のとおり端末ではstdout,stderr両方出力されるため違いがわからない。よって上記ではstdoutとstderrが分配できたとわかる。
$ { echo 'Out'; echo 'Err' >&2; } Out Err
1
,2
はファイルディスクリプタ(fd)である。
fd | path | named path | 和名 |
---|---|---|---|
0 |
/dev/fd/0 |
/dev/stdin |
標準入力 |
1 |
/dev/fd/1 |
/dev/stdout |
標準出力 |
2 |
/dev/fd/2 |
/dev/stderr |
標準エラー出力 |
fdへの出力を指定するときは識別子の前に&
を付与する。さもなくばファイル名とみなされる。たとえば以下は標準エラー出力でなくファイル2
に出力されてしまう。
echo 'A' >2
$ ls -1 ... 2 ...
2-2. ファイル
標準出力(stdout)をファイルへ出力する。
echo 'A' > a.txt
ファイルから標準入力(stdin)へ入力する。
cat < a.txt
cat
はstdinへの入力を待ち受ける。その後に入力値をstdoutへ出力するコマンドである。
2-3. 端末
端末で複数タブを開きそれぞれtty
コマンドを叩くと異なる結果が出る。
端末1
$ tty
/dev/pts/1
端末2
$ tty
/dev/pts/2
tty
は使用中の端末デバイスを表示するコマンドである/dev/pts/n
は端末を表す(n
は識別番号)
端末1から端末2へリダイレクトする。端末2にAAA
が表示される。
端末1
$ echo 'AAA' > /dev/pts/2
端末2で何も操作していないのにAAA
が表示されることを確認できる。
端末2
$ AAA
2-4. /dev/null
/dev/null
にリダイレクトすると消すことができる。以下はstdoutを消した。
echo A >/dev/null
stderrのみ消す。
{ echo Out; echo Err >&2; } 2>/dev/null
2-5. ファイルディスクリプタ
/dev/fd/3
にA
を出力する。/dev/fd/3
からcat
に入力する。/dev/fd/3
を閉じる。
exec 3< <(echo A); cat <&3; exec 3>&-;
bash4.1以降では{fd}
で空いているファイルディスクリプタを自動取得する。
exec {fd}< <(echo A); cat <&${fd}; exec {fd}>&-;
exec
は現在のプロセスで指定コマンドを発行するコマンド。
3. パイプ
echo -e 'A\nB\nC' | grep 'B'
|
でパイプを表す。パイプは前のコマンドにおけるstdoutを次のコマンドにおけるstdinにする。
上記コマンドはA<改行>B<改行>C
のテキストからB
を含む行を抜き出している。
echo -e 'B\nA\nC\nA' | sort | uniq
上記コマンドはB<改行>A<改行>C<改行>A
のテキストを1行ずつ辞書順で並び替えて重複を排除した結果を出力している。
ShellはUNIX哲学に基づいている。パイプを使ってコマンド連携させて様々な仕事をするようにできている。Unixユーティリティ一覧にあるようなコマンドを使う。その中でもsort
などのコマンドをフィルタと呼ぶ。フィルタはstdinからデータを受け入れてstdoutへ結果を出力する。この入出力形態によりパイプで連携できる。
3-1. ランダム文字列
/dev/urandom
でランダムなバイト列を取得する。
cat /dev/urandom
無限に出続けるのでCtrl
+C
(D
)で終了する。
先頭から100Byte分だけ出力させるなら以下。
cat /dev/urandom | head -c 100
出力結果は文字化けしていると思う。そこでアルファベットと数字だけを出力させる。(それ以外の文字を削除)
cat /dev/urandom | tr -dc "[:alnum:]" | head -c 100
16文字ごとに改行を挿入して折り返す。
cat /dev/urandom | tr -dc "[:alnum:]" | fold -w 16 | head -c 100
16字<改行>
を5行分だけ出力する。
cat /dev/urandom | tr -dc "[:alnum:]" | fold -w 16 | head -n 5
各コマンドの詳細は各コマンドの--help
を参照。(tr --help
等)
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13
- bash 4.4.12
$ uname -a Linux raspberrypi 4.14.98-v7+ #1200 SMP Tue Feb 12 20:27:48 GMT 2019 armv7l GNU/Linux