Membagi input untuk perintah yang berbeda dan menggabungkan hasilnya

8

Saya tahu cara menggabungkan hasil dari perintah yang berbeda

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

Saya tahu input pipa yang sama untuk perintah yang berbeda

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

Sekarang bagaimana cara menggabungkan perintah ini? Sehingga saya bisa melakukannya

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

Katakanlah saya punya file

file saya:

1
2
3
4

Saya ingin membuat file baru

1 4 2
2 3 4
3 2 6
4 1 8

Saya menggunakan

cat myfile | tee >(tac) >(awk '{print $1*2}') | paste

akan memberi saya hasil secara vertikal, di mana saya benar-benar ingin menempelkannya dalam urutan horizontal.

pengguna40129
sumber
Anda mungkin harus menulis dua aliran untuk memisahkan pipa nama, dan menggabungkannya dengan program monitor.
把 友情 留 在 无 盐

Jawaban:

8

Saat Anda memilih beberapa proses penggantian, Anda tidak dijamin mendapatkan output dalam urutan tertentu, jadi sebaiknya Anda tetap menggunakannya

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

Dengan asumsi cat myfilesingkatan dari beberapa pipeline mahal, saya pikir Anda harus menyimpan output, baik dalam file atau variabel:

output=$( some expensive pipeline )
paste -t',' <(commanda <<< "$output") <(commandb <<< "$output")

Menggunakan contoh Anda:

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

Pikiran lain: FIFO, dan satu saluran pipa

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
glenn jackman
sumber
bisakah saya menggunakan sth seperti / dev / fd / 3-9?
user40129
4

The yashshell memiliki fitur unik ( pipa redirection dan proses pengalihan ) yang membuat lebih mudah ada:

cat myfile | (
  exec 3>>|4
  tee /dev/fd/5 5>(commanda >&3 3>&-) 3>&- |
    commandb 3>&- |
    paste -d , /dev/fd/4 - 3>&-
)

3>>|4( pengalihan pipa ) menciptakan pipa di mana ujung penulisan pada fd 3 dan ujung membaca pada fd 4.

3>(commanda>&3)adalah redirection proses , sedikit seperti substitusi proses ksh / zsh / bash tetapi hanya redirection dan tidak menggantikan dengan /dev/fd/n. ksh's >(cmd)kurang lebih sama dengan yash' s n>(cmd) /dev/fd/n(ada nsebuah file descriptor yang dipilih oleh kshdi mana Anda tidak memiliki kontrol).

Stéphane Chazelas
sumber
3

Dengan 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
)

Kemudian gunakan sebagai:

$ echo abcd | pee 'paste -d,' 'tr a A' 'tr b B' 'tr c C'
Abcd,aBcd,abCd

Itu diadaptasi dari pertanyaan lain ini di mana Anda akan menemukan beberapa penjelasan terperinci dan petunjuk tentang keterbatasannya (waspadalah terhadap deadlock!).

Stéphane Chazelas
sumber
0

Untuk contoh khusus Anda seharusnya tidak perlu pastedan sisanya. Seringkali benar bahwa ketika kita menemukan batas dengan perangkat standar itu karena apa yang ingin kita lakukan dengan satu cara dapat dilakukan dengan cara lain. Seperti:

set 1 2 3 4
while [ "$#" -gt 0 ]
do    echo "$1" "$#" "$(($1*2))"
shift;done

... yang mencetak ...

1 4 2
2 3 4
3 2 6
4 1 8

Anda bisa mendapatkan file dengan konten seperti yang Anda sebutkan ke dalam "$@"array shell Anda seperti ...

set -f; IFS='
'; set -- $(cat)

Dan untuk memvalidasi nilai-nilai arg dalam satu loop seperti yang di atas, Anda dapat mengubah tes awal sedikit ...

while { [ "$1" -eq "${1-1}" ] ;} 2>&"$((2+!$#))"
do    echo "$1" "$#" "$(($1*2))"
shift;done  3>/dev/null >outfile

... yang mencetak kesalahan ke stderr hanya jika suatu baris yang dibacakan set -- $(cat)mengandung baris yang tidak seluruhnya terdiri dari satu bilangan bulat.

mikeserv
sumber