Diff of UNIX/基礎知識/リダイレクト、パイプ


#navi(UNIX/基礎知識)
#contentsx

*リダイレクト、パイプ [#v49ead61]

**共通 [#va69e67e]
リダイレクトによってコマンドの出力先、入力先を変更できます。
パイプによってコマンドの出力を別のコマンドの入力にすることができます。

例えば
 % ls
と実行すると、結果が端末上(ディスプレイ上)に出力されていたのが、
 % ls > test
とすると、test というファイルへ出力されて、そのファイルに書き込まれます。
この出力先を変える方法をリダイレクトと呼びます。

実は、ただ単に端末上への出力といっても、
標準出力と標準エラー出力というものがあります。
エラーメッセージは正規の出力ではないので、
標準エラー出力に出力するのが普通です。
さきほどの ls コマンドの出力は標準出力です。しかし例えば、
 % ls /aho
とすると、おそらく
 /aho not found
と出力されると思います(本当に存在しない限り)。先ほどと同様に
 % ls /aho > test
としてみてください。ファイルにはなにも書き込まれておらず、
端末上に出力されてしまったと思います。
見た目的には標準出力と標準エラー出力に違いはないように見えますが、
これで違うものだと認識してもらえたと思います。
標準エラー出力をリダイレクトするには > 記号ではなく別の記号を使うことになります。

では、最初からきっちりとリダイレクト、パイプを説明していきます。
 % [command] > [filename]
とすると、標準出力に出力されていたのが、ファイルへの書き込みになります。
この > 等をリダイレクト記号といいます。
このとき、もともとそのファイルに書込まれていた内容は消えてしまうので注意してください。
 % [command] >> [filename]
のように > を2つつなげて書くと、ファイル末尾への追加になります。

リダイレクトには < もありまして、これは入力先の変更です。
 % [command] < [filename]
標準入力にしか対応していないコマンドには便利です。
自分で作ったプログラムでファイル入力の部分をまだ書いていない
ときによく使ったりします。

パイプによってコマンドの出力を別のコマンドの入力にすることができます。
 % [command] | [command]
例えば
 % ls -a | grep '^\.'
などのように使用します。

もちろん、リダイレクト、パイプで標準エラー出力も扱うことができます。
しかしこの書式は csh, tcsh 系と sh, bash 系で全然ちがうものになります。
会津大学標準は csh なので、csh, tcsh 系を読むといいと思います。

**csh, tcsh 系での標準エラー出力の扱い [#g224bbd0]

csh, tcsh 系とはいっても実は sh, bash 系でもできますが・・・
 % [command] >& [filename]
とすると標準エラー出力もファイルに書き出せます。パイプの場合も同様に
 % [command] |& [command]
とすることもできます。コンパイルエラーが長いときに重宝します。
 % gcc [c file] |& more
のように使うことが多いです。ちょっとした技ですが、
 % [command] >& /dev/null
のようにすると何も出力しないようにできます。
/dev/null とは簡単にいうと、常に中身が空になるファイルです。
 % ( [command] > [filename] ) >& [filename]
のようにすると、標準出力と標準エラー出力を別々のファイルに保存できます。
() なしで書いてしまうと、後ろのファイルには両方とも書き出されてしまいます。
 % ( [command] > /dev/null ) >& [filename]
のようにすると標準エラー出力だけをファイルに書き出せます。
 % ( [command] > /dev/tty ) >& /dev/null
のようにすると標準出力だけ出力できます。/dev/tty とは端末を意味します。

//To make it easy, you may define alias like
// % alias errdrop "(\!* > /dev/tty) >& /dev/null"
//and use like 
// % errdrop [command]
**sh, bash 系での標準エラー出力の扱い [#g11150c2]

次に sh, bash の場合です。csh, tcsh 系にはできません。まず
 1 = 標準出力
 2 = 標準エラー出力 
のように番号づけされています(ちなみに 0 = 標準入力)。
よって普通のリダイレクトは
 % [command] 1>[filename] 
とすることもできます。
 % [command] 1>[filename] 2> [filename]
のようにして振り分けたりもできます。
 % [command] 1> /dev/null
 % [command] 2> /dev/null 
のようにしてどちらかだけ表示ということも容易にできます。
(上が 2 だけ表示。下が 1 だけ表示。)
 % [command] 2>&1
とすると標準エラー出力を標準出力にまとめることができます。逆に
 % [command] 1>&2
のように標準エラー出力にまとめることもできます。
ほかのコマンドに標準エラー出力と標準出力両方をパイプで渡したいなら、
 % [command] 2>&1 | [command]
のようにします。標準出力と標準エラー出力を両方ともファイルに書き出すには
 % [command] > [filename] 2>&1
のようにします。順番が微妙に逆なことに注意。() を使うのなら
 % ( [command] 2>&1 ) > [filename] 
でできます。こちらのほうが直感的にわかりやすい気がします。
標準エラー出力のみをパイプで渡すときには
 % [command] 2>&1 1> /dev/null | [command]
のようにします。これも逆になっています。() 使えば
のようにします。標準出力を /dev/null に捨てて、標準エラー出力(2)を標準出力に送る(1)という処理です。これも処理の順序と記述が逆になっています。() を使えば
 % ( [command] 1> /dev/null ) 2>&1 | [command]
のようになります。
*おまけ [#yed9dc6f]

**tee [#i8c27d46]

おまけとして、標準出力とファイルへの出力を同時にしたいときは、 
tee というコマンドを使います。
 % [command] | tee [filename]
この tee というコマンドは C言語でわかりやすく書けば 
(エラー処理がない、とかキャラクタしか使ってないのに printf とかはわざとです。)
 #include <stdio.h>
 
 int main(int argc,char *argv[]){
   FILE *fp;
   char c;
   fp=fopen(argv[1],"w");
   while(scanf("%c",&c)!=EOF){
     printf("%c",c);
     fprintf(fp,"%c",c);
   }
   fclose(fp);
 }
みたいなものにもう少し機能追加したようなコマンドです。
(知らなかったときは上のようなプログラム自分で書いて使ってました。
その無駄な努力を自分で誉めてあげたい。)

**set noclobber [#yd0fed6f]

さらに、おまけですが、リダイレクトによって既存のファイルを上書きしてしまううっかりミスをしたくない場合は、
 % set noclobber
としておくと、リダイレクトで上書きしようとした場合、
 [filename]: File exists.
のようにエラーメッセージがでてくれます。この場合、強制的に消して新しくするには[command] >! [filename]
のように ! を付けてやります。>> の場合にもエラーメッセージがでてしまうので、この場合も ! を付けてやります。

#navi(UNIX/基礎知識,,footer)
xrea