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

標準入出力 (stdin / stdout)

  • (イメージとして)マクドナルドで
    • ポテトを注文すると(標準入力)
    • ポテトが出てくる(標準出力)
  • Google 検索で
    • 「Linux 難しい」と検索すると(標準入力)
    • Linux 初心者向けの記事一覧がブラウザ画面に表示される(標準出力)
  • コンソールで
    • ls Enter とキーボード入力すると(標準入力)
    • 今いるディレクトリ内のファイル・ディレクトリ一覧がコンソール画面に表示される(標準出力)

標準エラー出力 (stderr)

  • stderr ( Shell )
  • シェルには標準出力とは別に、標準エラー出力というデータを出力する通り道が用意されている
    • コマンド実行で何かエラーが生じた場合、エラー表示を普通の出力データと区別して出力する必要があるため
      • エラー出力も標準出力に出すと、リダイレクションを使用している時にエラーが出てこなくなる

リダイレクション(リダイレクト)

出力先を切り替える

  1. ls 実行(標準入力)
  2. 結果はコンソール画面に表示される(標準出力)

  1. ls > list.txt 実行(標準入力)
  2. 結果はコンソール画面には表示されず、ファイル list.txt が生成され、その中に出力結果が記述される(標準出力)

「標準出力」とは、プログラムとOSのあいだでデータをやり取りをする「橋」の役割をします。プログラムが何かを標準出力に出力すると、それはOS(この場合はLinux)に渡されて解釈され、結果として画面に文字が表示される仕組みになっています。このような仕組みになっているおかげで、出力先を「コマンドを実行する段階で」変更することができます。

標準入出力すりかえのテクニック:ステップ・バイ・ステップ・シェルスクリプト(3) - @IT

# 本来は画面に出力される結果が、ファイルに書き込まれる
$ echo 'echo "Hello World"' > helloworld.txt
$ cat helloworld.txt
echo "Hello World"
  1. 入力されたコマンドechoをbashが認識する。
  2. 同時にbashは標準出力がhelloworldというファイルにリダイレクトされたことを認識する
  3. bashがechoコマンドを起動する直前にechoの標準出力をファイルへ変更する(すりかえる)
  4. echoコマンドは標準出力へ文字を出力する。echoはファイルへ変更されていることは全く意識しない。
  5. echoにより標準出力(bashによりファイルへすりかえられている)へ出力された情報をOSが受け取り、ファイルへ書き込む。

$ date > now
$ cat now
2022年 9月 6日 火曜日 01時29分41秒 JST
$ cal > now
$ cat now
      9月 2022
日 月 火 水 木 金 土
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

$ date >> now
$ cat now
      9月 2022
日 月 火 水 木 金 土
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

2022年 9月 6日 火曜日 01時30分12秒 JST
  • 標準出力・標準エラー出力は「情報の出口」
  • コマンドは実行結果を画面に出しているのではなく、この「情報の出口」に吐き出している
  • これを最終的に画面に出すのではなく、ファイルに書き出す・プリンターに出力するといった切り替えを指示するのがリダイレクト

入力元を切り替える

  • stdio ( Shell )
  • 標準入力の入力元を、キーボードからファイルにすることもできる
  • 仮に数字の乗算の結果を出力するコマンド a.out が あったとして
$ a.out
$ 3 2   <- キーボードから入力
6       <- a.outの出力した答え
$ cat data      <- 上記と同じ数値が書いてあるファイル
$ 3 2
$ a.out < data  <- リダイレクションでファイルから入力
6               <- a.outの出力した答え
  • 何らかの情報を「キーボードから受け取る」か「ファイルから受け取る」かの違いといったイメージ
  • 「何らかの処理を実行するプログラムファイル」と「何らかの加工をしたい元のファイル(csv など)」をリダイレクションで組み合わせると、決まったルーチンを自動化できそう?
$ cat list.txt
list.txt
vim.html

$ grep html < list.txt
vim.html

catというコマンドは詳しく言うと、「与えられた引数をファイルとして認識し、それらをつなげて標準出力へ出力する。引数が存在しない場合は、標準入力から読み込んで標準出力へ出力する」というコマンドです。今回の例題では、「引数が存在しない場合」の使い方に相当します。もともとはこのcatという名前は「ファイルをつなげる」という意味の英語のconcatenateから来ています。

標準入出力すりかえのテクニック:ステップ・バイ・ステップ・シェルスクリプト(3) - @IT

# 通常の cat
$ cat helloworld2
Helloworld2
cat <<EOF
Hello World
EOF

# cat の入力元を切り替える
$ cat < helloworld2
Helloworld2
cat <<EOF
Hello World
EOF

さきほどとは逆向きのリダイレクト(<)ですね。これは「標準入力」を「ファイル」に「すりかえ」することを表します。catにしてみれば、標準入力がすりかえられたことなどおかまいなしですから、最初の例と全く同じように標準入力から読み込んで標準出力へ出力しているだけです。

$ wc < test
       3       3      18 test
$ wc < test > rslt
$ cat rslt
       3       3      18 test

リダイレクションの種類

  • < file
    • 標準入力をfileに切替える
  • << word
    • 次にwordが行の先頭に出てくるまでの文字列を標準入力として使用する。
  • > file
    • 標準出力ををfileに切替える
    • もしfileが存在していた場合は古い内容は上書きされる。
  • >> file
    • 標準出力ををfileに切替える
    • 出力データはファイルの内容に追加される。
  • >& file
    • 標準エラー出力ををfileに切替える
    • もしfileが存在していた場合は古い内容は上書きされる。
  • >>& file
    • 標準エラー出力ををfileに切替える
    • 出力データはファイルの内容に追加される。
# 存在しないディレクトリを指定
$ ls zzzzz > err
ls: zzzzz: No such file or directory # エラーメッセージ

$ ls zzzzz >& err # > を >& にするとエラーは表示されない
$ cat err
ls: zzzzz: No such file or directory # ファイル「err」にエラーメッセージが記述される

ヒアドキュメント

$ cat << d
heredoc> a
heredoc> b
heredoc> c
heredoc> d
a
b
c
$ cat <<EOF
line1
line2
line3
EOF
$ cat <<EOF > test
line1
line2
line3
EOF

$ cat test
line1
line2
line3

まとめなど

  • 標準出力
    • コマンド実行で得られた結果を吐き出すのは画面だけではない
      • ファイルやプリンターなど
    • 各種コマンドの仕事は「画面上に吐き出すこと」ではなく、得られた結果を返すだけ(return みたいな)
      • それをどこに吐き出すか指令するのがリダイレクト
  • 標準入力
    • 標準出力の逆で、入力を受け付けるのはキーボードだけではない
      • すでにあるファイルを突っ込み、欲しい出力結果として取り出すといった使い方ができる
  • リダイレクトを使うことで、ファイル作成にもいろんなパターンが広がる
    • grep で特定の内容を抽出して出力
    • sort で並び替えて出力
    • uniq で重複削除して出力
    • touch は厳密にはファイル作成コマンドではないとのこと
  • 単一カラムのような簡単な内容であれば、わざわざエクセルを開かずともコマンドラインから欲しい結果を得ることができる