Übergeben von zwei Argumenten an einen Befehl mithilfe von Pipes

22

Normalerweise müssen wir nur ein Argument übergeben:

echo abc | cat
echo abc | cat some_file -
echo abc | cat - some_file

Gibt es eine Möglichkeit, zwei Argumente zu übergeben? So etwas wie

{echo abc , echo xyz} | cat
cat `echo abc` `echo xyz`

Ich könnte einfach beide Ergebnisse zuerst in einer Datei speichern

echo abc > file1
echo xyz > file2
cat file1 file2

Aber dann könnte ich versehentlich eine Datei überschreiben, was nicht in Ordnung ist. Dies geht in ein nicht interaktives Skript über. Grundsätzlich brauche ich eine Möglichkeit, die Ergebnisse von zwei beliebigen Befehlen an zu übergeben, catohne in eine Datei zu schreiben.


UPDATE: Entschuldigung, das Beispiel maskiert das Problem. Während es zu { echo abc ; echo xyz ; } | catfunktionieren scheint, liegt die Ausgabe am echos, nicht am cat.

Ein besseres Beispiel wäre, { cut -f2 -d, file1; cut -f1 -d, file2; } | paste -d,was nicht wie erwartet funktioniert.

Mit

file1:
a,b
c,d

file2:
1,2
3,4

Erwartete Ausgabe ist:

b,1
d,3

BEHOBEN:

Verwendung Prozess Substitution :cat <(command1) <(command2)

Alternativ können Sie Named Pipes erstellen, indem Sie Folgendes verwenden mkfifo:

mkfifo temp1
mkfifo temp2
command1 > temp1 &
command2 > temp2 &
cat temp1 temp2

Weniger elegant und ausführlicher, funktioniert aber gut, solange Sie sicherstellen, dass Temp1 und Temp2 nicht vor der Hand existieren.

Goweon
quelle
1
Das bringt mich dazu, meinen Kopf zu kratzen. Sie möchten zwei verschiedene Befehle an eine einzelne Katze weiterleiten?
user606723
2
Sie wissen, dass "Piping" und "Argumente" zwei völlig unabhängige Begriffe sind, oder?
Ignacio Vazquez-Abrams
@Ignacio err ... Ich bin nicht so vertraut mit Linux, also kenne ich den Unterschied nicht wirklich. Ich habe immer gedacht, dass Piping bedeutet, dass das vorherige Ergebnis als Argument herangezogen wird. Möchtest du mich aufklären?
Goweon
@firebat nein, Pipe bedeutet, dass die Standardausgabe des vorherigen Befehls als Standardeingabe des nächsten Befehls verwendet wird. Sie können immer noch Argumente haben, die ein anderes Konzept sind.
Rich Homolka
Was Ihren Update-Text betrifft, kommt die Ausgabe von cat. Sie möchten lediglich, dass die Anweisungen von cat getrennt angezeigt werden. Dies ist jedoch nicht möglich, da sie in einem Stream serialisiert werden.
Rich Homolka

Antworten:

17

Ich denke, Sie möchten 'Process Substitution' http://tldp.org/LDP/abs/html/process-sub.html . Es funktioniert auch unter zsh, hat jedoch mehr Optionen und die Syntax kann unterschiedlich sein.

/dev/fd/somethingFür jede Ersetzung wird eine Pseudodatei ( ) erstellt. Das ist ziemlich nützlich. Der Befehl kann nur als Stream gelesen werden, dh er kann nicht mit fseek hin und her gehen. Es muss als ein Strom von Bytes wie eine Pipe gelesen werden.

Ihre Beispiele dienen als Prozesssubstitution:

cat <(echo abc) <(echo xyz)
paste -d, <(cut -f2 -d, file1) <(cut -f1 -d, file2)

Stellen Sie sich das als Werkzeug vor, um einen Prozess zu verwenden und so zu tun, als wäre es eine Datei ohne temporäre Dateien.

(Aus meiner früheren Antwort )

Reiche Homolka
quelle
2

Die geschweiften Klammern haben tatsächlich funktioniert, weil der Pipe-Operator die Standardausgänge der gruppierten Befehle mit den Standardeingängen des dritten Befehls verbindet.

Sie können feststellen, dass der Ausdruck nicht von den Echos stammt, indem Sie einen Befehl ausführen, der keine Standardeingabe verwendet. Beispielsweise { echo 1; echo 2;} | echo 3wird 3 anstelle von 1 \ n2 \ n3 gedruckt.

Dies ist jedoch nicht das, was Sie wollten, da die beiden Befehle in den geschweiften Klammern auf dieselbe Ausgabe schreiben, was catihren Ergebnissen gleicht . Um zwei unterschiedliche Ergebnisse als Argumente für Befehle wie zu generieren paste, müssen Sie eine temporäre Datei oder eine Named Pipe verwenden.

Sie können mktempeine eindeutige temporäre Datei mkfifoerstellen oder eine FIFO-Pipe-Datei erstellen.

billc.cn
quelle
Ein großes Dankeschön für Ihre Antwort, ich habe viele Tage nach dieser Lösung gesucht und schließlich Ihre Antwort hier gefunden.
Saeed Falsafin
2

Ich mag xargs Als Beispiel möchte ich die Größe aller mysql-Datenverzeichnisse unter / usr / local finden

osx: lokaler Benutzer $ pwd
/ usr / local
osx: lokaler Benutzer $ ls | grep mysql
MySQL
mysql-5.0.51a-osx10.5-x86_64
mysql-5.0.51b-osx10.5-x86_64
mysql-5.1.39-osx10.5-x86_64
mysql-5.6.17-osx10.7-x86_64
os x: lokaler Benutzer $ ls | grep mysql | sudo xargs du -sh
4.0K MySQL
2,8G mysql-5.0.51a-osx10.5-x86_64
 10G mysql-5.0.51b-osx10.5-x86_64
 25G mysql-5.1.39-osx10.5-x86_64
753M mysql-5.6.17-osx10.7-x86_64
osx: lokaler Benutzer $ 

xargs

tupfen
quelle