リダイレクトとパイプ


目次

1 シェル

1.1 シェル

シェル (shell) は,ユーザーがコマンド行に打ち込んだコマンド等を解 釈し,コンピュータに実行させる役割をもつプログラムです 1。 ユーザーがコンピュータにログインすると,そのユーザーのためにシェルが動き出しま す。 これをログインシェル (login shell) といいます。 ユーザーがコマンド行にコマンドをタイプして実行できるのは, シェルが動いているからです。

シェルには幾つかの種類があり, ユーザーがログインシェルとし て何というシェルを用いるかは,予め管理者が設定しています。 シェルが持つ機能や使い方はシェル毎に違いますので, echo $SHELL を実行して,利用中のシェルを確認しましょう2。 /bin/tcsh と出力されますね。 皆さんが使っているシェルは tcsh (ティーシーシェル) です。

1.2 コマンド入力の支援機能

tcsh が持つ機能の一例として, コマンド入力を助ける機能を幾つか紹介します。 なお,ここで紹介する機能は,他の最近よく使われるシェルでも利用できます。

1.2.1 ヒストリの一覧と利用

過去に実行したコマンド行の履歴をヒストリ (history) といいます。 Windows のコマンドプロンプトと同様に, tcsh でも上向きや下向きの矢印キーを使えば,過去に実行したコマンド行を再 度使うことができます。

次のコマンドはヒストリ一覧を表示します。

history
ヒストリ一覧から,過去に実行したコマンド行を選んで再実行するには
!n
に続いて <ENTER> を押します 3。ここで n はヒストリ一覧中のヒストリ番号です。

1.2.2 コマンド行の補完

コマンド名やファイル名の一部をタイプしてから <TAB> を押すことで, 残りを自動的に補う (補完) ことができます。 この機能を使うとコマンドやファイル名のタイプミスを防ぐこともできます。
  1. [コマンド名の補完] コマンド行に his とタイプして <TAB> を押してみましょう。 続いて <ENTER> を押しましょう。

  2. [補完候補の表示] コマンド行に hi と打ってから <TAB> を押してみましょう。

    hi で始まるコマンドは複数ありますので,まだ補完はされません。

  3. 続いて s をタイプしてコマンド行を his としてから <TAB> を押し てみましょう。続いて <ENTER> を押しましょう。

  4. [ファイル名の補完] まず,カレントディレクトリに存在するファイルの名前を ls コマンド を実行して確認してください。 続いて, cat の引数に,既存のファイル名の一部をタイプしてから <TAB> を押してみましょう。 ファイル名が補完されたら <ENTER> を押しましょう。

2 リダイレクトとパイプ


2.1 復習 -- コマンド出力の保存

2.1.1 コマンド出力のファイルへの保存

コマンド command が画面に表示する内容を,ファイル名が file であるファイルに格納するには
command [argument ...] > file
とします。 ここで [argument ... ] は,command に引数を与えたけ れば argument ... の箇所に与えられることを意味します。 file として,存在しないファイルを指定すれば,file が自動的に作成されます。 file が既存のファイルならば,その内容は command の出力で上書きさ れます4

cal 2006 > year を実行してください。

2.1.2 コマンド出力の既存ファイルへの追加

すでに存在するファイルにコマンド出力を追加したい場合には > の代わ りに >> を使い,
command [argument ...] >> file
とします。

2.1.3 練習

  1. date コマンドと cal コマンドを普通に実行して,画面の表示を確認し てください。

  2. >>> の使い方を確かめるために,以下を順に実行し てください。一行実行する度に cat コマンドでファイル now の内容を 確認してください。
     date > now
     cal > now
     date >> now
    

2.2 標準出力・標準エラー出力とリダイレクト

2.2.1 標準出力と標準エラー出力

ここでは,コマンドの実行結果が画面に表示される仕組みをより正確に説明します。

多くの UNIX コマンドは ``標準出力'' と ``標準エラー出力'' と呼ばれる情報 の出口を持っています。

  1. 標準出力 stdout (standard output): コマンドの実行結果が出力される
  2. 標準エラー出力 stderr (standard error): エラーメッセージ等のコマンド実行に係わる付加的な情報が出力される
コマンドは,実行結果などを画面ではなく,これらの出口に出力します。 画面にコマンドの実行結果等が表示されるのは,図に示すように,通常は標準出力と 標準エラー出力が画面に接続されているためです。
\includegraphics*{stdout.eps}

2.2.2 標準出力のリダイレクト

コマンドを実行する際,標準出力の接続先をファイルに変更するようシェルに対 して指示することができます。このような接続先の変更操作(切り替え)をリダイレクト(redirection) といいます。 第 2.1 節で紹介した >>> は,共に実 行するコマンドの標準出力の接続先のみをファイルに切り替えるリダイ レクトです。標準出力のリダイレクトを用いれば,通常は画面に表示されるコマ ンドの実行結果を,ファイルに保存することができます。
\includegraphics*{redirect_stdout.eps}
例えば,
cal 2006 > year
を実行して結果がファイル year に保存されるのは, 「> year」の指定により cal コマンドの標準出力が, 画面ではなくファイル year に接続されるためです。

なお,tcsh で標準出力と標準エラー出力の接続先を共にファイルに切り替えるには >&>>& を使います。

注意

cal 2006 > year において, 「2006」は cal コマンドに対して出力の変更を指示するものなので, cal コマンドの引数です。 一方, 「> year」は シェルに対して標準出力の接続先変更を指示しているのであり, cal コマンドの動作を変更するものではありません。 したがって, 「> year」は cal コマンドの引数ではありません。

2.3 標準入力とリダイレクト

2.3.1 キーボードからの入力と入力の終わり -- CTRL-d

次の操作を試してみましょう。
  1. wc year を実行し,wc がどんなコマンドだったかを思い出してください5
  2. 次に,引数を与えないで wc を実行してみましょう。
    何も起きないどころかプロンプトも表示されません。
  3. ここで,キーボードから ls と打って,<ENTER> を押しましょう。
    プロンプトが表示されないままでコマンドを打っても,そのコマンドは 実行されません。
  4. キーボードから I like you. と打ち込んで <ENTER> を押しましょ う。
    まだ何も起こりませんね。
  5. 今度は Ctrl キーを押しながら d キーを押してください。これからは CTRL キーを押しながら d キーを押すことを CTRL-d と表記します。
    wc の実行結果が出力され,プロンプトが現れました。wc は実行を終 えました。

ファイル名を指定せずに wc を実行すると,wc はキーボードからの入力を処理 します6。2. においてプロンプトが表示されなかったのは, wc が実行中であり,キーボードからの入力を待っている状態だったからです。

4. で使った CTRL-d は「入力の終わり (正確には,ファイルの終り; EOF = End Of File)」を意味するキーです。 wc は CTRL-d が入力されたのでキーボードからの読み込みを終了し, 実行結果を画面に出力しました7

なお,上の操作ではキーボードから 2 行 4 単語を入力しましたから,行数と単 語数に関しては wc は正しい結果を出力しています。一方,文字数については, 画面に表示されている入力文字数(空白文字を含む)より 2 文字分多いはずです。 これは,行末に入力した <ENTER> を,wc が文字として数えているからです。 実際,<ENTER> で入力したものは特殊な文字であって,通常の文字として表示 される代りに,画面上では改行として表示されているのです。

注意:コマンドの強制終了 -- CTRL-c

CTRL-c はコマンドの実行を強制的に終了させる働きをします。 上記の例で CTRL-d の代わりに CTRL-c を押すと, wc は読み込みを完了する前に終わってしまいます。 したがって文字数等の出力は行われません。 両者の違いに注意しましょう。

コマンドを実行したけれど動作がおかしい,とか, プロンプトが戻るまでの時間が長すぎる, といった場合には CTRL-c によるコマンドの終了を試してみるといいでしょう。 コマンド行でタイプミスをしてしまい,最初から打ち直したい場合にも, CTRL-c が使えます。 ただし,コマンドを正常終了できる場面では,正規の終了操作をすべきです。

2.3.2 標準入力

wc コマンドのように,キーボードからデータを受け取って処理できる UNIX コマンドでは,多くの場合, 正確には 標準入力 stdin (standard input) という入口から入力を読み込みます。 標準入力は,通常はキーボードに接続されているので, その結果として,コマンドはキーボードから入力を受け取るのです。
\includegraphics*{stdin.eps}
この図では,コマンドの標準エラー出力と標準出力の接続先(画面)を省略しています。 また,これ以降の図において,標準エラー出力の描画は略します。

2.3.3 標準入力のリダイレクト

標準出力の接続先を切り換えできるのと同様に,標準入力の接続先を切り換える こと (リダイレクト) も可能です。
\includegraphics*{redirect_stdin}
command が標準入力からの入力を受け付けるコマンドであるとき, キーボードの代わりにファイル file から入力を受け取るよう にするには
command [argument] < file
を実行します。ここで [argument] は,command に引数を与え たければ argument に指定できることを表します。

2.3.3.1 練習

  1. wc < year を実行しましょう。 これは wc の標準入力の接続先を,キーボードからファイル year に切り換える例です。

  2. 1. と同じく標準入力のリダイレクトを使って,ファイル year を wc に読み込ませて処理しましょう。ただし,今回は,wc にオプション引数 を指定することにより,year の行数のみを求めてください。 wc のオプション引数は man wc で調べてください。

注意

wc の引数に既存のファイル名を指定して, wc year のように実行した場合, wc は引数のファイル year を直接読み込んで処理します。 標準入力のリダイレクトである wc < year と出力は同じですが, wc 内部での動作は異なります。

2.3.4 標準入出力の同時リダイレクト

コマンドの標準入力と標準出力を同時に切り換えることもできます。 例えば,標準入力を year に,標準出力を wc.out に切り換えて wc コマンドを実 行するためには
wc < year > wc.out
とします。 これを試したら,不要な wc.out は削除しましょう。

2.4 パイプ

2.4.1 準備 -- 一時ファイルを使った複数コマンド処理

who コマンドを使うと,同じコンピュータを使っているユーザーの一覧が得られます。 who と wc を使ってコンピュータにログインしているユーザーの人数を調べてみましょう。

  1. まず,who コマンドを引数なしで実行し,どんな出力が得られるかを確 認してください。

    一行につき 1 ユーザーの情報が出力されますね。 who の出力から行数を求めれば,ログインしている延べユーザー数がわ かります。

  2. who コマンドの出力を,リダイレクトを使ってファイル user に保存します。
    who > user
    cat コマンド等で user の中身を確認してください。

  3. wc コマンドにオプション -l (エル) を指定して,ファイル user の行数を調べます。
    wc -l user
    ユーザー数がわかりましたね。

  4. ファイル user は不要になりましたので,削除してください。
    rm user
2. と 3. で行ったことを図にすると次のようになります。
\includegraphics*{12_who_wc.eps}

2.4.2 コマンドの連結 -- パイプ

あるコマンドの標準出力を,ファイルではなく,別のコマンドの標 準入力に直接接続することが可能です。その操作をパイプと呼びます。 パイプは,コマンド行において,一連のコマンドを「縦棒 (|)」で区切っ て記述することによって行います。パイプによって連結された一連のコマンドを パイプライン (pipeline) と言います。

なお,コマンドの標準出力と標準エラー出力の両方を次のコマンドの標準入力に 接続するには,tcsh の場合,| の代わりに |& とします。

例1: who と wc でログイン中のユーザー数を得る

前節の操作をパイプを使って行います。
who | wc -l
この状況を図示したのが次の図です。 パイプと共に wc を実行する場合, wc は標準入力 (stdin) から入力を受け取る必要がありますので, wc の引数にファイル名を指定してはいけません。
\includegraphics*{12_pipe_who_wc.eps}

例2: ls の出力を more で見る

一画面に収まらない ls の出力を more コマンドで 1 ページずつ見る例です。 ここでは /etc ディレクトリ内の全ファイルの詳細情報を ls コマンドで表示します。
ls -la /etc | more
more は引数にファイル名が与えられれば, そのファイルを直接読み込んで表示しますが, ファイル名を与えずにリダイレクトやパイプと共に用いると,標準入力から入力を受け取ります。 次の図では ls の引数 (-la /etc) の記述は省略しています。
\includegraphics*{4_pipe}
動作の概要は以下のとおりです。
  1. ls が実行結果を標準出力に出力します。

    ls の標準出力をパイプによって more の標準入力に接続しているので, ls の実行結果は画面には出力されません。

  2. more が ls の実行結果を標準入力から受け取り,標準出力を通じて画面 に表示します。
    1. more は,一画面分以上の入力を受け取ると対話的な動作をしま すので,一画面分の表示を終えたところで表示を止め,ユーザー からの命令を待っている状態になります。
    2. ユーザーがスペースキー等を押して全ページを表示させ終えるか, q 等を押すことで more を終了させると, パイプライン全体が終了し,プロンプト が帰ってきます。

2.4.3 パイプとリダイレクトの同時利用

次の例は,ls の出力を辞書順の逆順に並べ替えて表示します8
ls | sort -r
結果を画面ではなく,ファイル rlist に入れたければ
ls | sort -r > rlist
を実行します。このようにパイプと標準入出力のリダイレクトを同時に利用する ことが可能です。

2.4.4 コマンドの多段連結

command1 が標準出力 (stdout) に結果を出力するコマンドであり,command2command3 が標準入力 (stdin) から入力を読み取っ て結果を標準出力 (stdout) に出力するコマンドならば,
command1 | command2 | command3
により,次の図に示す多段のパイプが可能です。 これにより,command1 の出力が command2 で処理され,さらに command3 で処理されます。


\includegraphics*{4_multi_pipe}
なお,これまでと同様に,パイプラインの中の各コマンドには引数を与えること もできます。また,4つ以上のコマンドをパイプすることもできますし,その出 力をリダイレクトすることも可能です。

2.4.5 フィルタ

先の command2command3 のように,標準入力と標準出力を使っ た入出力が可能なコマンドをフィルタ (filter) といいます。フィルタは パイプラインの中で利用できるコマンドです。 この授業で紹介したコマンドでは
cat, grep, sort, wc
はフィルタです。 各コマンドの動作は man コマンド等で確認できます。


3 問題

  1. echo コマンドは引数に与えた文字列を標準出力に出力するコマンドです。

    echo とリダイレクトを使って,自分の学生番号と名前の入ったファイル myname を作ってください。

  2. ホームディレクトリに,内容が
    hakodate
    sapporo
    asahikawa
    kushiro
    iwamizawa
    であるファイル campus はありますか。無ければ echo コマンドを使っ て作成してください。echo は複数回実行してかまいません。

  3. tr は文字の置換を行うコマンドです。 tr は標準入力から入力を読み込み,引数での指定に従って文字を 置換し,結果を標準出力に出力します。

    1. tr コマンドの動作を確認するために,tr a A を実行してから
      hakodate
      sapporo
      
      を標準入力(キーボード)から入力してください。入力を終えた ら tr コマンドを正常終了させてください。

    2. tr では文字集合の置換もできます。tr a-z A-Z を実行 してみましょう。入力には前項と同じものを与えてください。

    では,ファイル campus の内容をすべて大文字にしたものを,ファイル CAMPUS に保存しましょう。tr コマンド,および標準入力と標準出力の リダイレクトを使ってください。

  4. カレントディレクトリに存在するファイル(. で始まるものは除く)の 個数を求めましょう。

    1. まず,ls の出力を一度ファイルに保存してから,その中身を確 認してください。そのファイルを wc コマンドに読み込んで,期 待する結果が得られたか確認してください。

      うまくいったら,ここで作成したファイルは削除しましょう。

    2. パイプを使って上記と同様のことをしてください。

  5. ファイル campus の 中身を,sort コマンドで辞書順に並べ替えて画面に表示しましょう。 さらにその表示を全て大文字にしましょう。

  6. grep は,引数で与えた文字列パターンを含む行のみを抽出して,標準出 力に出力するコマンドです。
    grep pattern file...
    の書式で実行すると,grep はfile... から patten を含む 行のみを抽出しますが,file... を省略すると,標準入力から入 力を読み込みますので,フィルタとして利用できます。

    まず,grep ko campus や grep sa campus を実行して, grep の動作を確認してください。

    次に who の出力の中から自分の情報のみを出力しましょう。 grep とパイプを使います。

  7. cat コマンドは,引数にファイル名を指定せずに実行すると, 標準入力から入力を読み込みこんでそのまま出力します。 オプション -n をつけると行番号をつけて出力します。

    さて,who コマンドの出力をを辞書順に並べて表示しましょう。 さらに,その結果に行番号を付けて出力しましょう。



脚注

... 釈し,コンピュータに実行させる役割をもつプログラムです1
これは,シェル利用の一形態です。 他の形態 (シェルスクリプトのためのコマンドインタプリタ) でシェルを利用することもあります。
... を実行して,利用中のシェルを確認しましょう2
echo は引数をそのま ま出力するコマンドですが,コマンド行における $ はシェルにとって特別な意 味があるため,画面に $SHELL とは表示されません。
... を押します3
知っていて便利なヒストリ機能には次のものもあります。 !-n (n だけ前に実行したコマンド行), !! (一つ前に実行したコマンド行 (!-1 と同じ)), !str (str で始まる最も最近のコマンド行)。 ここで n には正の整数を,str には適当な文字列(通常はコマンド 名またはその始めの一部) を記述します。これらに続いて <ENTER> を押すと,当 該コマンド行の内容が実行されます。
... れます4
set noclobber を実行することで,> によ る既存ファイルの上書きを禁じる設定にすることができます。その場合, > のかわりに >! を使えば,強制的に既存のファイルを上書 きできます。
... がどんなコマンドだったかを思い出してください5
man wc
... します6
正確に言えば,標準入力からの入力を処理します。標準入力に ついては後の章で学習します
... 実行結果を画面に出力しました7
プロンプトに対してコマンドを入力せ ずに CTRL-d だけを打つと,設定によってはログアウトするかもしれません。 注意しましょう。
... の出力を辞書順の逆順に並べ替えて表示します8
リダイ レクトやパイプと共に ls を実行すると,デフォルトでは ls はオプション -1 (数字の1) を与えたときと同じく,一行につき1ファイル名を出力します。