Wie verkette ich stdin und einen String?

107

Wie verkette ich stdin mit einem String wie diesem?

echo "input" | COMMAND "string"

und bekomme

inputstring
Noam Ross
quelle

Antworten:

119

Ein bisschen hacky, aber dies könnte der kürzeste Weg zu tun , was man in der Frage gestellt (ein Rohr verwenden zu akzeptieren stdoutaus echo "input"als stdinzu einem anderen Prozess / Befehl ein :

echo "input" | awk '{print $1"string"}'

Ausgabe:

inputstring

Welche Aufgabe versuchst du genau zu erfüllen? Mehr Kontext kann Ihnen mehr Orientierung für eine bessere Lösung geben.

Update - Antwort auf Kommentar:

@ NoamRoss

Die idiomatischere Art, das zu tun, was Sie wollen, ist dann:

echo 'http://dx.doi.org/'"$(pbpaste)"

Die $(...)Syntax wird als Befehlssubstitution bezeichnet . Kurz gesagt, es führt die Befehle aus, die in einer neuen Subshell enthalten sind, und ersetzt die stdoutAusgabe dort, wo sie $(...)in der übergeordneten Shell aufgerufen wurde. Sie würden also tatsächlich Folgendes erhalten:

echo 'http://dx.doi.org/'"rsif.2012.0125"
Sampson-Chen
quelle
1
Vielen Dank! Das funktioniert super. Die genaue Aufgabe, die ich zu erfüllen versuche, besteht darin, eine Zeichenfolge aus der Zwischenablage (einem DOI) zu entnehmen und ihr eine URL voranzustellen. Damit mache ich pbpaste | awk '{print "http://dx.doi.org/"$1}'und bekommehttp://dx.doi.org/10.1098/rsif.2012.0125
Noam Ross
5
@ Sampson-Chen, ich würde verwenden '{print $0"string"}', um die ganze Sache zu schnappen.
Roman Newaza
3
Es wird tatsächlich stringan jede Zeile angehängt . Versuchen Sie es echo 'input'\n'another line' | awk '{print $0"string"}'.
Tomékwi
55

Verwenden cat -Sie diese $()Option , um aus stdin zu lesen, und setzen Sie sie ein, um die nachfolgende Newline wegzuwerfen

echo input | COMMAND "$(cat -)string"

Warum lassen Sie die Pipe jedoch nicht fallen und greifen bei einer Befehlsersetzung auf die Ausgabe der linken Seite zu:

COMMAND "$(echo input)string"
Glenn Jackman
quelle
1
Hier ist ein praktisches Beispiel: find ~ / other_program / lib -name "* .jar" | tr '\ n' ':' | Echo "$ (cat -) ~ / java_app / classes"
Ashwin Jayaprakash
2
Dies funktioniert bei mir in bash, aber in zsh erhalte ich "cat: -: Eingabe- / Ausgabefehler". Irgendeine Idee, was das verursachen könnte?
Jaymmer - Wiedereinsetzung Monica
"COMMAND" steht für die Lösung und "Echo Input" für einen komplizierteren Prozess. Das Argument "-" für cat ist nur erforderlich, wenn andere Dateiargumente vorhanden sind. Andernfalls ist es die Standardeinstellung. Sie meinten also: Echoeingang | echo $ (cat) string
Denis Howe
45

Ich benutze oft Pipes, daher ist dies eine einfache Möglichkeit, stdin voranzustellen und zu ergänzen:

echo -n "my standard in" | cat <(echo -n "prefix... ") - <(echo " ...suffix")
prefix... my standard in ...suffix
rupert160
quelle
2
Vielen Dank! Das ist eigentlich ein sehr cooles Beispiel für die Verwendung von pipeundcat
Alex Ivasyuv
1
Dies sollte die beste Antwort sein
Chris Koston
1
Warum nicht einfach : echo "my standard in" | echo -e "prefix\n$(cat -)\nsuffix"? Oder die besser lesbare Version:echo "my standard in" | printf "%s\n%s\n%s\n" "prefix" "$(cat -)" "suffix"
MiniMax
1
@MiniMax Da die Antwort bei Streams gut funktioniert, funktioniert sie bei großen Standardwerten.
Anishpatel
1
@anishpatel Meine Version funktioniert auch für große stdin. Kein Unterschied.
MiniMax
11

Sie können es mit sed tun:

seq 5 | sed '$a\6'
seq 5 | sed '$ s/.*/\0 6/'

In Ihrem Beispiel:

echo input | sed 's/.*/\0string/'
Vytenis Bivainis
quelle
9

Es gibt einige Möglichkeiten, dies zu erreichen. Ich persönlich denke, das Beste ist:

echo input | while read line; do echo $line string; done

Eine andere Möglichkeit besteht darin, "$" (Zeilenendezeichen) in einem sed-Befehl durch "string" zu ersetzen:

echo input | sed "s/$/ string/g"

Warum bevorzuge ich das erstere? Weil es eine Zeichenfolge sofort mit stdin verkettet, zum Beispiel mit dem folgenden Befehl:

(echo input_one ;sleep 5; echo input_two ) | while read line; do echo $line string; done

Sie erhalten sofort die erste Ausgabe:

input_one string

und dann nach 5 Sekunden erhalten Sie das andere Echo:

input_two string

Wenn Sie dagegen "sed" verwenden, wird zuerst der gesamte Inhalt der Klammer ausgeführt und dann "sed", also der Befehl

(echo input_one ;sleep 5; echo input_two ) | sed "s/$/ string/g"

gibt beide Zeilen aus

input_one string
input_two string

nach 5 Sekunden.

Dies kann sehr nützlich sein, wenn Sie Funktionen aufrufen, deren Ausführung lange dauert und die über die Ausgabe der Funktion kontinuierlich aktualisiert werden sollen.

Simone
quelle
Tatsächlich verarbeitet die Option sed auch jede Eingabezeile sofort.
Tomékwi
Für eine einzelne Eingabezeile ist die einfachste Lösung die Echoeingabe | (read v; echo $ {v} string) Das ist reine Shell und erfordert keinen zusätzlichen Prozess wie sed.
Denis Howe
7

Ich weiß, dass dies einige Jahre zu spät ist, aber Sie können dies mit der Option xargs -J erreichen:

echo "input" | xargs -J "%" echo "%" "string"

Und da es sich um xargs handelt, können Sie dies in mehreren Zeilen einer Datei gleichzeitig tun. Wenn die Dateinamen drei Zeilen haben, wie zum Beispiel:

Adam
Bob
Charlie

Du könntest es tun:

cat names | xargs -n 1 -J "%" echo "I like" "%" "because he is nice"
user2635263
quelle
1
Sieht cool aus, -Jscheint aber nicht Standard / üblich zu sein. Unter Linux (wo xargsist ein Teil davon GNU findutils) erhalte ich die Fehlermeldung: Auf xargs: invalid option -- 'J'welchem ​​System ist das?
Arielf
3
-Jist für die Mac-Version. Für Linux -Iführt die gleiche Funktion aus.
user2635263
1
Vielen Dank! sehr hilfreich. Bitte beachten Sie, dass diese vereinfachte Version unter Linux genauso gut funktioniert: cat names | xargs -I% echo "I like % because he is nice"IOW: Keine Notwendigkeit für -n 1( xargsAufrufe echoeinmal pro Eingabezeile, da -Iimpliziert -L1). Außerdem scheinen alle separaten Arg-Anführungszeichen redundant zu sein.
Arielf
3

Der Befehl, den Sie veröffentlicht haben, verwendet die Zeichenfolge "input" und verwendet sie als stdin-Stream von COMMAND. Dies würde nur dann zu den gewünschten Ergebnissen führen, wenn COMMAND zuerst den Inhalt seines stdin und dann seine Befehlszeilenargumente ausgedruckt hat.

Es scheint, als ob das, was Sie tun möchten, der Befehlsersetzung näher kommt.

http://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html#Command-Substitution

Mit der Befehlsersetzung können Sie eine Befehlszeile wie folgt haben:

echo input `COMMAND "string"`

Dies wertet zuerst COMMAND mit "string" als Eingabe aus und erweitert dann die Ergebnisse dieser Befehlsausführung auf eine Zeile, wobei ersetzt wird, was zwischen den '`' Zeichen steht.

Max DeLiso
quelle
und natürlich @NaomRoss, es sei denn, Sie müssen die Bourne-Shell verwenden oder andere verrückte "Portabilitäts" -Mandate haben, verwenden Sie die moderne Befehlsersetzung wie echo input $(COMMAND "string")anstelle von Backticks. Viel Glück für jeden.
Shellter
1

Katze wird meine Wahl sein: ls | cat - <(echo new line)

clarkttfu
quelle
sed ist ein
zeilenbasierter
0

Funktioniert auch:

seq -w 0 100 | xargs -I {} echo "string "{}

Erzeugt Zeichenfolgen wie:

string 000
string 001
string 002
string 003
string 004

...

cy8g3n
quelle