Teilen Sie eine Eingabe für einen anderen Befehl und kombinieren Sie das Ergebnis

8

Ich weiß, wie man das Ergebnis verschiedener Befehle kombiniert

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

Ich kenne die gleiche Eingabe zu verschiedenen Befehlen

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

Wie kann man nun diesen Befehl kombinieren? Damit ich es tun kann

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

Angenommen, ich habe eine Datei

meine Datei:

1
2
3
4

Ich möchte eine neue Datei erstellen

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

ich benutzte

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

würde mir das Ergebnis vertikal geben, wo ich sie wirklich in horizontaler Reihenfolge einfügen möchte.

user40129
quelle
Möglicherweise müssen Sie zwei Streams schreiben, um Namenspipes zu trennen, und sie mit einem Monitorprogramm kombinieren.
6 友情 留 在 无 6

Antworten:

8

Wenn Sie zu mehreren Prozessersetzungen wechseln, wird nicht garantiert, dass Sie die Ausgabe in einer bestimmten Reihenfolge erhalten. Halten Sie sich also besser daran

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

Angenommen, es cat myfilesteht für eine teure Pipeline, dann müssen Sie die Ausgabe entweder in einer Datei oder in einer Variablen speichern:

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

Anhand Ihres Beispiels:

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

Ein anderer Gedanke: FIFOs und eine einzelne Pipeline

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
quelle
kann ich etw wie / dev / fd / 3-9 verwenden?
user40129
4

Die yashShell verfügt über einzigartige Funktionen ( Pipeline-Umleitung und Prozessumleitung ), die dies dort einfacher machen:

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

3>>|4( Pipeline-Umleitung ) Erstellt eine Pipe, bei der sich das Schreibende auf fd 3 und das Leseende auf fd 4 befindet.

3>(commanda>&3)ist eine Prozessumleitung , ein bisschen wie eine ksh / zsh / bash-Prozessersetzung, führt jedoch nur die Umleitung durch und ersetzt sie nicht durch die /dev/fd/n. ksh's >(cmd)ist mehr oder weniger dasselbe wie yash' s n>(cmd) /dev/fd/n(es ngibt einen Dateideskriptor, von kshdem Sie keine Kontrolle haben).

Stéphane Chazelas
quelle
3

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

Dann verwenden als:

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

Dies ist aus dieser anderen Frage übernommen, in der Sie einige detaillierte Erklärungen und Hinweise zu den Einschränkungen finden (Vorsicht vor Deadlocks!).

Stéphane Chazelas
quelle
0

Für Ihr spezielles Beispiel sollte es keine Notwendigkeit geben pasteund der Rest. Es ist oft richtig, dass wenn wir mit dem Standard-Toolset auf eine Grenze stoßen, dies daran liegt, dass das, was wir auf eine Weise tun möchten, auf eine andere Weise getan werden kann. Sowie:

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

... was druckt ...

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

Sie können eine Datei mit Inhalten, die Sie erwähnen, in Ihr Shell- "$@"Array wie ...

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

Und um die arg-Werte in einer Schleife wie der obigen zu validieren, können Sie den anfänglichen Test ein wenig ändern ...

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

... der nur dann einen Fehler an stderr ausgibt, wenn eine mit eingelesene Zeile eine Zeile set -- $(cat)enthält, die nicht vollständig aus einer einzelnen Ganzzahl besteht.

mikeserv
quelle