kjo*_*kjo 4 bash zsh signals shell-script stdout
我经常想要执行一个需要的操作
stdout管道(我们称之为管道pipeline-before)分成两个并行流;stdin到两个单独的管道(pipeline-between-0和pipeline-between-1);stdout流;stdin给另一个管道 ( pipeline-after)。在 (3) 中,“按严格的顺序”是指来自的所有输出,例如,pipeline-between-0应该出现在合并的输出流中,位于来自 的任何输出之前pipeline-between-1。
整个事情可以用图表来表示:
pipeline-before --.--- pipeline-between-0 -.
\ \
`- pipeline-between-1 ---`-- pipeline-after
Run Code Online (Sandbox Code Playgroud)
pipeline-between-0这样的/对的一个例子pipeline-between-1可以是:
head -n 1 | tr 'a-z' 'A-Z'tail -n +2 | sort -t $'\t' -k1,1在英语中,人们会将这种组合描述为“使第一行全部大写,并按第一列对其余行进行排序”。
问:有通用的 shell 语法来表达这样的操作吗?
我对这个问题的答案感兴趣zsh和bash。
这是一种通常不起作用的语法:
$ pipeline-before | tee >( pipeline-between-0 ) | pipeline-between-1 | pipeline-after
Run Code Online (Sandbox Code Playgroud)
此语法失败有两个原因:
pipeline-between-1经常出现在 的某些输出之前pipeline-between-0。SIGPIPE)。我确实尝试了以下策略(我承认,我并不 100% 理解):
pipeline-before --.--- pipeline-between-0 -.
\ \
`- pipeline-between-1 ---`-- pipeline-after
Run Code Online (Sandbox Code Playgroud)
AFAICT,这种语法似乎解决了上面列出的第一个问题(即基于一些非正式测试,pipeline-between-0和的输出pipeline-between-1以正确的顺序显示)。但不幸的是,最终的输出仍然被截断,至少在某些情况下是这样。
也许您只需要命名管道(FIFO)?
以下示例:
{ seq 1 100000 | grep 1$ & seq 1 100000 | grep 2$ ; } > unsorted
Run Code Online (Sandbox Code Playgroud)
应返回 file 中分别以 1 和 2 结尾的数字的混合结果unsorted。我们希望它们排序(所有数字都以 1 结尾,然后所有数字都以 2 结尾),因此现在创建两个命名管道,每个结果一个,然后按照所需的顺序将它们连接起来。
mkfifo stream{1,2}
{ seq 1 100000 | grep 1$ >stream1 & seq 1 100000 | grep 2$ > stream2 ; } &\
cat stream1 stream2 > sorted
Run Code Online (Sandbox Code Playgroud)
检查文件的顺序是否相同:
diff -q {un,}sorted
Run Code Online (Sandbox Code Playgroud)
(它们应该不同)并查看排序后的排序是否按预期排序:
sed 1,10000q sorted | grep 2$
Run Code Online (Sandbox Code Playgroud)
(应该没有结果,而unsorted文件应该返回数据)
bash命名管道对于和 的工作方式应该相同zsh。
或者用伪代码最通用的表达式:
tee输入流(您的“之前的管道”)通过和 FIFO复制到任意数量的并行流中in-i。out-i(您的“i 之间的管道”)。mkfifo {in,out}-{0..n}
pre-cmd | tee in-0 in-1 ... in-n | cat >/dev/null &
cmd-0 <in-0 >out-0 &
cmd-1 <in-0 >out-0 &
....
cmd-i <in-n >out-n &
cat out-0 out-1 ... out-n | after-cmd
Run Code Online (Sandbox Code Playgroud)
我使用cat >/dev/null而不是cat >in-n出于泛化的原因,同样的(可能)cat最终是多余的。
例子:
mkfifo {in,out}-{0..2}
seq 0 100 | tee in-{0..2} | cat >/dev/null &
grep '33$' <in-0 >out-0 &
awk '$1<2' <in-1 >out-1 &
sed '/^.\{1,2\}$/d' <in-2 >out-2 &
cat out-2 out-0 out-1 | tr '\n' '-'
Run Code Online (Sandbox Code Playgroud)
结果:100-33-0-1-