無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

標準エラーのリダイレクト


標準出力と標準エラーをファイルに書き出す場合、以下のように指定します。
[root@localhost ]# cat aaa >log 2>&1
[root@localhost ]# cat log
cat: aaa: そのようなファイルやディレクトリはありません
これを下記のように指定すると上手くいきません。
[root@localhost ]# cat aaa 2>&1 >log
cat: aaa: そのようなファイルやディレクトリはありません
標準エラーを標準出力にリダイレクトして、それをlogファイルにリダイレクトするという流れから、下記の方が自然に思えるのですが・・・。

この誤解は、シェルでのリダイレクトの処理は、ファイルディスクリプタの差し替えのみにもかかわらず、出力までの流れとして解釈してしまうところにあるのではと思います。

2>&1はシェルでdup2(1,2)をコールします。(>&の&は、つづく引数はファイルディスクリプタと。と認識しています)そしてdup2はdup3をコールします。dup2とdup3の違いはclose-on-execフラグをセットするかどうかの違いで、dup2はその引数を0としてdup3をコールしているだけです。

要はdup3の処理は、newfdのファイルIDのfile構造体を示すファイルディスクリプタテーブルに、ファイルID oldfdで指し示しているfile構造体のポインタをセットし直しておるだけです。
SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
{
   :
       err = expand_files(files, newfd);
       file = fcheck(oldfd);
   :
       fdt = files_fdtable(files);
       tofree = fdt->fd[newfd];
   :
       rcu_assign_pointer(fdt->fd[newfd], file);
   :
       if (tofree)
               filp_close(tofree, files);
       return newfd;
   :
}
なお、expand_files関数は、newfdディスクリプタが、現在のファイルディスクリプタテーブルの範囲内かどうかチェックするもので、範囲外なら新規ファイルディスクリプタテーブルを確保(拡張)し、このファイルディスクリプタテーブルをプロセスのファイルディスクリプタテーブルに設定しなおします。なお標準エラーの場合2ですから、この関数は何もしないで返ってきます。


cat aaa 2>&1 >logでは、dup2(1,2)でcatプロセス(シェルの子プロセス)の標準エラーディスクリプタテーブルは、標準出力ディスクリプタテーブルをポイントすることになり、この時点で両方とも画面に出力されるわけです。そして>logで、標準出力ディスクリプタテーブルのみがlogのfile構造体をポイントしますが、標準エラーは標準出力のfile構造体のままということです。したがってエラー出力はファイルに書き出されません。

cat aaa >log 2>&1では、cat aaa >logで、まず標準出力ディスクリプタテーブルがlogのfile構造体を指し示し、2>&1でこのlogのfile構造体を指し示している標準出力ディスクリプタテーブルを、標準エラーディスクリプタテーブルが指し示すようにすることで、結果的に標準エラーもlogファイルのfile構造体を指し示すというわけです。

補足1
manでdupを見ると、 dup() と dup2() は、ファイルディスクリプタ oldfd の複製を作る。となっていて、file構造体を新規に複写して、それをセットするものと思っていました。ソースを見る限り、file構造体をただ共有しているだけです。新規に複写すると、標準出力と標準エラーをlogファイルに書き出す場合、お互いが独自のオフセットポインター(ファイルのオフセットはfile構造体毎に所有)で上書きすることになり、期待するファイル出力が得られません。処理としてfile構造体は共有する処理ではだめということです。

補足2
パイプも処理的にはリダイレクトすなわちファイルディスクリプタの差し替えにすぎません。シェルからだと、1つのコマンドに対して1つのコマンドということですが、1つのコマンドの標準出力を複数のコマンドの入力とすることも可能なわけです。

最終更新 2010/07/26 16:59:31 - north
(2010/07/26 16:59:31 作成)