第4章:リダイレクションによるファイル操作

最初に

第1章から書式や変数などの話しばかりで少し飽きてきましたが、どれもシェルスクリプトを書くためには必要な知識なので何とかがんばっていきたいと思いまする。
第4章は25ページほどで、ファイル操作関連の話しがメイン。やっとこさなんだかプログラムっぽっくなってきました。

ファイルディスクリプタ

ファイルに何か書き込みたいときは、ファイルディスクリプタを使ってファイルアクセスをする。このファイルディスクリプタの番号のうち、0,1,3番は予約されており重要なので覚えるべし。

  • 0番 標準入力(通常はキーボードからの入力を受け取る)
  • 1番 標準出力(通常は端末画面への出力、これに書き込めば端末画面にメッセージを出力できる)
  • 2番 標準エラー (通常は端末画面への出力)

リダイレクション

通常の入力や出力先を変更することをリダイレクトと言う。リダイレクト記号として「>」「<」を使用する。「>」でファイルに書き込むと、元々のデータがクリアされるので、追記させたい場合は「>>」で行う。
「>」でファイルへリダイレクトすると、正確には1番のディスクリプタを経由するもをファイルへ向けると言う意味になる。エラーはディスプリタ番号2なので、「>」でファイルに向けてもエラーメッセージはファイルに書き込まれない。それを踏まえ、通常のリダイレクトを正確に書くと下記のようになる。

$ cat xxx 1> abc
xxx: No such file or directory

上記のようにすると、エラーメッセージはディスプリタ2番なのでファイルabcに書き込まれず、画面に表示される。
もし、エラーメッセージをファイルに向けるリダイレクトは以下の通り。これを利用すれば、エラーメッセージだけ別のファイルで保存することができる。

$ cat xxx 2> abc
$ cat: xxx: No such file or directory

もし、エラーメッセージと通常の出力結果も1つのファイルに入れたい場合は下記のようにする。

$ cat abc xxx > nnn 2>&1

リダイレクトの記号「>」は、どの場所に書いてもいいが、通常は最後に書くのが普通。もしリダイレクトを複数に書いたりした場合は「左から右」へとなる。例えばあるコマンドの実行結果やエラーメッセージをすべて消し去るときの例は下記のようになる。下記のコマンドだと、コマンドの標準出力を/dev/nullへ書き込み、それから標準エラー(ファイルディスプリタ2)も標準出力(ファイルディスプリタ1)へ行くように書き込んでいる。すでに標準エラーは/dev/nullへ向かっているので、結果、標準エラーも/dev/nullへ行く。

コマンド > /dev/null 2>&1

リダイレクトは、変数でも可能。

STDOUT=/dev/null
コマンド > $STDOUT

標準出入力を扱うものとしてパイプ(|)がある。パイプの左側の標準出力をパイプの右側の標準入力にすると言う意味になる。

リダイレクトを使った書き込み

echoコマンドは標準出力にメッセージを出力する。もし、echoコマンドで標準エラーにメッセージを出力したい場合は下記のように書く。

echo "Error messages." 1>&2

もし、3以上のファイルディスプリタへ書き込みしたい場合は

$ echo abcdef 1>&8
$ exec 8> hhh
$ echo abcdf 1>&8

ディスプリタは、リダイレクト先のファイルがなければ自動で作ってくれる。

リダイレクトでの読み込み

標準入力も、もちろんリダイレクトできる。キーボードからの入力の代わりにファイルをそのままリダイレクトする。例としては以下の通り。

commmand < file

また、ファイルではなく書いてある文字列とかをそのまま入力することも可能。

command << word

これを「ヒア・ドキュメント」と言う。

ファイルサイズを0にする。

/dev/nullを利用する。エディタで開いて中身を消しても1バイトだけ残ってしまうので。下記のどちらでも大丈夫。

$ cat /dev/null > file
$cp /dev/null file

ヒア・ドキュメント(Here Documents)

1つのシェルスクリプトの中に、入力する文字も同時に書いてしまう方法のこと。最初に現れた文字列がもう一度出てきたら、そこまでを入力として認識する。一般的にはENDなどを使用。以下にサンプルをば。最初のEND以降で、2回目のENDまでが標準入力として扱う。

$ cat << END
> This is a
> input data.
> END
|

上記のとき、変数を標準入力から渡すことも可能。逆に、$DIRなどを変数としてではなく文字列として「$DIR」として扱わせる方法は「\$DIR」と文字列だけをクォートする方法と、下記のようにヒア・ドキュメント全体をクォートする方法がある。後者の方がわかりやすくていい。

$ DIR=document
$ cat << \END
> This is a
> here $DIR.
> END
This is a
here $DIR.

ほかにもクォートする方法として、ENDをシングルクォーテーションで括弧っても同じようになります。('END')<<の後にハイフン(-)をつけると、ヒア・ドキュメントの部分の先頭のタブ(スペースはダメ)は入力されていないものとして扱う。インデントを無視させたいときに使用する。例えば下記のような書き方をしておけばわかりやすい。

then
      command  <<- END
            This is a here document.
      END
fi

入門UNIXシェルプログラミング―シェルの基礎から学ぶUNIXの世界

入門UNIXシェルプログラミング―シェルの基礎から学ぶUNIXの世界