リダイレクト/パイプを使用するとき、bashは実際にstdin / stdout / stderrをどのように変更しますか?

リダイレクト/パイプを使用するとき、bashは実際にstdin / stdout / stderrをどのように変更しますか?

残念なことに、私が見つけたのはリダイレクトの構文であるか、リダイレクトがどのように機能するかについての表面的な情報だけでした。

私が知りたいのは、パイプやリダイレクトを使用するときにbashが実際にどのように変わるかですstdin。たとえば、次を実行する場合:stdoutstderr

ls -la > diroutput.log

stdoutにどのように変わりますかlsdiroutput.log

私はこれが次のように動作すると思います。

  • Bash を実行してfork(2)独自のコピーを作成します。
  • bashプロセスをフォークして、次のようなものを有効にしますstdoutdiroutput.logfreopen(3)
  • 分岐されたbashプロセスが実行されるか、execve(2)同様のexec機能が独自に置き換えられ、bash設定を使用するようになりましたlsstdout

しかし、それは私の経験に基づいた推測です。

ベストアンサー1

strace -f私はこの問題を解決するためにCを使って簡単な概念証明を書くことができました。

execve私が思ったように、bashは呼び出す前に子プロセスのファイル記述子を操作するようです。

動作原理はls -la > diroutput.logおおよそ次のとおりです。

  • バッシュ通貨fork(2)
  • 分岐されたbashプロセスは出力リダイレクトを確認しdiroutput.logますopen(2)
  • フォークされたbashプロセスは、ファイル記述子をシステムコールstdoutに置き換えます。dup2(2)
  • execve(2)bashはそれを置き換える実行可能イメージを呼び出して、すでに設定されてlsいるイメージを継承します。stdout

関連するシステムコールは次のとおりです(strace出力)。

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

おすすめ記事