分割不同命令的输入并合并结果


8

我知道如何合并不同命令的结果

paste -t',' <(commanda) <(commandb)

我知道将相同的输入传递给不同的命令

cat myfile | tee >(commanda) >(commandb)

现在如何结合这些命令?这样我就可以

cat myfile | tee >(commanda) >(commandb) | paste -t',' resulta resultb

说我有一个文件

myfile:

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

会给我垂直的结果,我真的要水平地粘贴它们。


您可能必须编写两个流来分隔名称管道,然后将它们与监视程序结合在一起。
把友情留在无盐2015年

Answers:


8

准备进行多个流程替换时,不能保证以任何特定顺序获取输出,因此最好坚持使用

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

我可以使用/ dev / fd / 3-9之类的东西吗?
user40129

4

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/nksh>(cmd)或多或少相同yashn>(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

这是从另一个问题改编而成的,您将在其中找到有关限制的一些详细说明和提示(请注意死锁!)。


0

对于您的特定示例,应该没有其他需要了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输出错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.