残念ながら、私が見つけたものはすべてリダイレクトの構文、またはリダイレクトがどのように機能するかについての浅い情報に基づいているため、これを理解することができませんでした。
私が知りたいのは、パイプまたはリダイレクトを使用したときに、bashが実際にstdin
/stdout
/stderr
をどのように変更するかです。たとえば、次のように実行します。
_ls -la > diroutput.log
_
stdout
のls
を_diroutput.log
_にどのように変更しますか?
私はそれがこのように機能すると思います:
fork(2)
を実行して、それ自体のコピーを作成しますfreopen(3)
のようなものを使用して、それをstdout
から_diroutput.log
_に設定します。execve(2)
または同様のexec関数を実行して、それ自体をls
に置き換えます。これにより、bashによるstdout
セットアップが使用されます。しかし、それは私の知識に基づく推測です。
_strace -f
_を使用して、Cで小さな概念実証を書くことでそれを理解することができました。
私が思ったように、bashはexecve
を呼び出す前に、子プロセスでファイル記述子を操作するだけのようです。
_ls -la > diroutput.log
_の仕組みは次のとおりです(大まかに):
fork(2)
を呼び出しますopen(2)
を使用してファイル_diroutput.log
_を開きます。dup2(2)
syscallを使用してstdout
ファイル記述子を置き換えますexecve(2)
を呼び出して、実行可能イメージをls
に置き換えます。これにより、すでに設定されているstdout
が継承されます。関連するシステムコールは次のようになります(strace
output):
_6924 open("diroutput.log", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
6924 dup2(3, 1) = 1
6924 close(3) = 0
6924 execve("/bin/ls", ["ls", "-la"], [/* 77 vars */]) = 0
_