我知道如何组合不同命令的结果
paste -t',' <(commanda) <(commandb)
我知道将相同的输入传递给不同的命令
cat myfile | tee >(commanda) >(commandb)
现在如何组合这些命令?这样我就能做到
cat myfile | tee >(commanda) >(commandb) | paste -t',' resulta resultb
说我有一个文件
我的文件:
1
2
3
4
我想制作一个新文件
1 4 2
2 3 4
3 2 6
4 1 8
我用了
cat myfile | tee >(tac) >(awk '{print $1*2}') | paste
会给我垂直的结果,我真的想按水平顺序粘贴它们。
答案1
当您进行多个进程替换时,不能保证以任何特定顺序获得输出,因此您最好坚持使用
paste -t',' <(commanda < file) <(commandb < file)
假设cat myfile
代表一些昂贵的管道,我认为您必须将输出存储在文件或变量中:
output=$( some expensive pipeline )
paste -t',' <(commanda <<< "$output") <(commandb <<< "$output")
使用你的例子:
output=$( seq 4 )
paste -d' ' <(cat <<<"$output") <(tac <<<"$output") <(awk '$1*=2' <<<"$output")
1 4 2
2 3 4
3 2 6
4 1 8
另一个想法:FIFO 和单一管道
mkfifo resulta resultb
seq 4 | tee >(tac > resulta) >(awk '$1*=2' > resultb) | paste -d ' ' - resulta resultb
rm resulta resultb
1 4 2
2 3 4
3 2 6
4 1 8
答案2
该yash
外壳具有独特的功能(管道重定向和进程重定向)让事情变得更容易:
cat myfile | (
exec 3>>|4
tee /dev/fd/5 5>(commanda >&3 3>&-) 3>&- |
commandb 3>&- |
paste -d , /dev/fd/4 - 3>&-
)
3>>|4
(管道重定向) 创建一个管道,其中写入端位于 fd 3 上,读取端位于 fd 4 上。
3>(commanda>&3)
是进程重定向,有点像 ksh/zsh/bash 进程替换,但只是进行重定向,而不替换为/dev/fd/n
. ksh
's>(cmd)
或多或少与yash
's相同n>(cmd) /dev/fd/n
(有一个您无法控制的n
文件描述符选择)。ksh
答案3
和zsh
:
pee() (
n=0 close_in= close_out= inputs=() outputs=()
merge_command=$1; shift
for cmd do
eval "coproc $cmd $close_in $close_out"
exec {i}<&p {o}>&p
inputs+=($i) outputs+=($o)
eval i$n=$i o$n=$o
close_in+=" {i$n}<&-" close_out+=" {o$n}>&-"
((n++))
done
coproc :
read -p
eval tee /dev/fd/$^outputs $close_in "> /dev/null &
" exec $merge_command /dev/fd/$^inputs $close_out
)
然后用作:
$ echo abcd | pee 'paste -d,' 'tr a A' 'tr b B' 'tr c C'
Abcd,aBcd,abCd
这是改编自这另一个问题您将在其中找到一些详细的解释和限制提示(小心死锁!)。
答案4
对于您的特定示例,应该不需要paste
其余的。通常,当我们遇到标准工具集的限制时,这是因为我们想要用一种方式做的事情可以用另一种方式来做。例如:
set 1 2 3 4
while [ "$#" -gt 0 ]
do echo "$1" "$#" "$(($1*2))"
shift;done
...打印...
1 4 2
2 3 4
3 2 6
4 1 8
您可以获得一个包含您在 shell"$@"
数组中提到的内容的文件,例如...
set -f; IFS='
'; set -- $(cat)
要验证像上面这样的循环中的 arg 值,您可以稍微更改初始测试......
while { [ "$1" -eq "${1-1}" ] ;} 2>&"$((2+!$#))"
do echo "$1" "$#" "$(($1*2))"
shift;done 3>/dev/null >outfile
set -- $(cat)
...仅当读入的行包含不完全由单个整数组成的行时,才会向 stderr 打印错误。