不幸的是,我没有运气弄清楚这一点,因为我发现的所有内容都只是重定向的语法,或者有关重定向如何工作的浅层信息。
我想知道的是当您使用管道或重定向时bash实际上如何stdin
改变。例如,如果您执行:stdout
stderr
ls -la > diroutput.log
它如何改变stdout
为ls
?diroutput.log
我认为它的工作原理是这样的:
- Bash 运行
fork(2)
以创建自身的副本 - 分叉的 bash 进程将其设置
stdout
为diroutput.log
使用类似的东西freopen(3)
- 分叉的 bash 进程运行
execve(2)
或类似的 exec 函数来替换自身,ls
现在使用stdout
bash 的设置
但这只是我有根据的猜测。
答案1
我能够使用strace -f
C 语言并编写一个小的概念证明来解决这个问题。
看来 bash 只是在调用之前操作子进程中的文件描述符,execve
正如我所想的那样。
工作原理如下ls -la > diroutput.log
(大致):
- bash 调用
fork(2)
- 分叉的 bash 进程看到输出重定向并
diroutput.log
使用open(2)
. - 分叉的 bash 进程
stdout
使用dup2(2)
系统调用替换文件描述符 - bash 调用
execve(2)
替换它的可执行映像,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