やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Shellの特殊ファイルとその操作(リダイレクト、パイプ)

 LinuxのShellはすべてファイルとして制御する。

成果物

目次

  1. 特殊ファイル
  2. リダイレクト
    1. 標準ストリーム
    2. ファイル
    3. 端末
    4. /dev/null
    5. ファイルディスクリプタ
  3. パイプ
    1. ランダム文字列

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/3Aを出力する。/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