为了进一步理解 bash,我尝试复制它的一些功能。现在我正在实现重定向和管道功能。要进一步理解这些概念,除了阅读文档(重定向和管道),我一直在尝试一些特殊情况,并且想出了这个我很难理解的情况:
bash-3.2$ echo test > file | tr -d t < file | wc > file ; cat file
0 0 0
我希望该命令的输出是1 1 3
,但它却输出0 0 0
.我在 zsh 中尝试了相同的命令,输出是我所期望的,所以看来我的一些假设对于 bash 来说是不正确的。为了便于参考,我将把提供的命令视为cmd1 | cmd2 | cmd
.这就是我认为执行命令时发生的情况:
- 标准输出的指令1被重定向到标准输入的指令2。
- 标准输出的指令2被重定向到标准输入的指令3。
- 指令1被执行:
- 文件被创建或截断。
- 标准输出
echo test
被重定向到文件。 - 这回声命令被执行并且“test”被保存到文件。
- 指令2被执行:
- 标准输入
tr -d t
被重定向到文件。 - 这t命令被执行并且“测试”读取文件变为“es”并输出到指令3。
- 标准输入
- 指令3被执行:
- 文件被截断。
- 标准输出
wc
被重定向到文件。 - 这厕所命令以“es”作为输入执行,“1 1 3”被保存到文件。
显然我的一些假设是错误的,我将非常感谢对它们的所有可能的更正。
我还尝试过其他命令,例如:
bash-3.2$ echo test > file | tr -d t < file | wc >> file ; cat file
test
1 1 3
bash-3.2$ echo test > file | tr -d t < file | wc > file2 ; cat file ; cat file2
test
1 1 3
这些测试使我相信我的假设在事情的执行顺序上甚至在截断发生的那一刻可能是错误的。不管是什么,我很乐意感谢任何解释或进一步的帮助。
答案1
管道中的命令同时运行,因此从/向同一文件读取和写入取决于进程的调度方式。
特别是,在步骤 4.2 中,无法保证文件在tr
开始读取时包含任何数据,因为 a)echo
左侧可能尚未写入任何内容,b) 中的重定向可能已wc > file
截断文件echo
写的。
我不确定为什么你要在那里使用第一个管道,因为到/从文件的重定向会覆盖管道。你在那里做的事情与
echo test > file & tr -d t < file | wc > file; wait; cat file
一般来说,它并没有好多少,因为它仍然包含所有相同的种族,但至少它没有令人困惑的管道运算符。
Zsh 的multios
不同之处在于,它使多个输出重定向打印到全部目标,以及从中读取的多个输入重定向全部来源。而不是像标准 shell 那样只有最后一个。