Comment concaténer stdin et une chaîne?

108

Comment concaténer stdin en une chaîne, comme ça?

echo "input" | COMMAND "string"

et obtenir

inputstring
Noam Ross
la source

Réponses:

119

Un peu hacky, mais c'est peut-être le moyen le plus court de faire ce que vous avez demandé dans la question (utilisez un tube pour accepter stdoutde echo "input"comme stdinvers un autre processus / commande:

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

Production:

inputstring

Quelle tâche essayez-vous exactement d'accomplir? Plus de contexte peut vous aider à trouver une meilleure solution.

Mise à jour - réponse au commentaire:

@NoamRoss

La façon la plus idiomatique de faire ce que vous voulez est alors:

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

La $(...)syntaxe est appelée substitution de commande . En bref, il exécute les commandes incluses dans un nouveau sous-shell et substitue sa stdoutsortie à l'endroit où le a $(...)été appelé dans le shell parent. Ainsi, vous obtiendriez, en effet:

echo 'http://dx.doi.org/'"rsif.2012.0125"
sampson-chen
la source
1
Merci! Cela fonctionne très bien. La tâche exacte que j'essaie d'accomplir est de prendre une chaîne du presse-papiers (un DOI) et d'y ajouter une URL, donc avec cela, je le fais pbpaste | awk '{print "http://dx.doi.org/"$1}'et j'obtienshttp://dx.doi.org/10.1098/rsif.2012.0125
Noam Ross
5
@ sampson-chen, j'utiliserais '{print $0"string"}'pour saisir le tout.
Roman Newaza
3
Il s'ajoute en fait stringà chaque ligne. Essayez echo 'input'\n'another line' | awk '{print $0"string"}'.
tomekwi
55

utilisez cat -pour lire à partir de stdin, et mettez-le $()pour jeter la nouvelle ligne de fin

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

Cependant, pourquoi ne pas laisser tomber le tube et saisir la sortie du côté gauche dans une substitution de commande:

COMMAND "$(echo input)string"
Glenn Jackman
la source
1
Voici un exemple pratique: find ~ / other_program / lib -name "* .jar" | tr '\ n' ':' | echo "$ (cat -) ~ / java_app / classes"
Ashwin Jayaprakash
2
Cela fonctionne pour moi dans bash, mais dans zsh j'obtiens "cat: -: Erreur d'entrée / sortie". Une idée de ce qui pourrait causer cela?
jaymmer - Réintégrer Monica
"COMMAND" représente la solution et "l'entrée écho" pour un processus plus compliqué. L'argument "-" de cat n'est requis que s'il y a d'autres arguments de fichier, sinon c'est la valeur par défaut. Donc, ce que vous vouliez dire était: entrée d'écho | echo $ (cat) string
Denis Howe
46

J'utilise souvent des tubes, donc cela a tendance à être un moyen facile de préfixer et de suffixer stdin:

echo -n "my standard in" | cat <(echo -n "prefix... ") - <(echo " ...suffix")
prefix... my standard in ...suffix
Rupert160
la source
2
Merci! C'est en fait un exemple très cool d'utilisation pipeetcat
Alex Ivasyuv
1
Cela devrait être la meilleure réponse
Chris Koston
1
Pourquoi pas simplement echo "my standard in" | echo -e "prefix\n$(cat -)\nsuffix":? Ou, la version la plus lisible:echo "my standard in" | printf "%s\n%s\n%s\n" "prefix" "$(cat -)" "suffix"
MiniMax
1
@MiniMax Parce que la réponse fonctionne bien avec les flux, elle fonctionnera pour les grands stdin.
anishpatel
1
@anishpatel Ma version fonctionnera aussi pour les grands stdin. Aucune différence.
MiniMax
11

Vous pouvez le faire avec sed:

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

Dans votre exemple:

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

Il y a quelques moyens d'y parvenir, je pense personnellement que le meilleur est:

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

Un autre peut être en remplaçant "$" (caractère de fin de ligne) par "string" dans une commande sed:

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

Pourquoi je préfère le premier? Parce qu'il concatène une chaîne à stdin instantanément, par exemple avec la commande suivante:

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

vous obtenez immédiatement la première sortie:

input_one string

puis après 5 secondes, vous obtenez l'autre écho:

input_two string

D'un autre côté, en utilisant "sed", il exécute d'abord tout le contenu de la parenthèse et ensuite il le donne à "sed", donc la commande

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

affichera les deux lignes

input_one string
input_two string

après 5 secondes.

Cela peut être très utile dans les cas où vous effectuez des appels à des fonctions qui prennent beaucoup de temps et que vous souhaitez être continuellement mis à jour sur la sortie de la fonction.

Simone
la source
En fait, l' option sed traite également chaque ligne d'entrée instantanément.
tomekwi
Pour une seule ligne d'entrée, la solution la plus simple est l'entrée écho | (lire v; echo $ {v} string) C'est un shell pur donc ne nécessite aucun processus supplémentaire comme sed.
Denis Howe
7

Je sais que cela a quelques années de retard, mais vous pouvez le faire avec l'option xargs -J:

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

Et comme il s'agit de xargs, vous pouvez le faire sur plusieurs lignes d'un fichier à la fois. Si le fichier 'noms' a trois lignes, comme:

Adam
Bob
Charlie

Vous pourriez faire:

cat names | xargs -n 1 -J "%" echo "I like" "%" "because he is nice"
user2635263
la source
1
Ça a l'air cool sauf que -Jça ne semble pas être standard / commun. Sous Linux (où xargsfait partie de GNU findutils), j'obtiens l'erreur: Sur xargs: invalid option -- 'J'quel système est-ce?
arielf
3
-Jest pour la version Mac. Pour Linux -Iremplit la même fonction.
user2635263
1
Merci! très utile. Veuillez noter que sous Linux, cette version simplifiée fonctionne aussi bien: cat names | xargs -I% echo "I like % because he is nice"IOW: pas besoin de -n 1( xargsappelle echoune fois par ligne d'entrée de toute façon, puisque l' -Iimplique -L1) De plus, toutes les citations séparées d'arg, semblent redondantes.
arielf
3

La commande que vous avez postée prendrait la chaîne «entrée» l'utiliser comme flux stdin de COMMAND, ce qui ne produirait pas les résultats que vous recherchez à moins que COMMAND n'imprime d'abord le contenu de son stdin, puis imprime ses arguments de ligne de commande.

Il semble que ce que vous voulez faire est plus proche de la substitution de commandes.

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

Avec la substitution de commande, vous pouvez avoir une ligne de commande comme celle-ci:

echo input `COMMAND "string"`

Cela évaluera d'abord COMMAND avec "string" comme entrée, puis étendra les résultats de l'exécution de cette commande sur une ligne, en remplaçant ce qui se trouve entre les caractères '`'.

Max DeLiso
la source
et bien sûr @NaomRoss, à moins que vous ne soyez obligé d'utiliser Bourne shell ou d'avoir d'autres mandats de «portabilité» fous, vous utiliserez la substitution de commande moderne comme echo input $(COMMAND "string"), plutôt que des contre-indications. Bonne chance à tous.
shellter
1

chat sera mon choix: ls | cat - <(echo new line)

Clarkttfu
la source
sed est une commande basée sur la ligne qui ne fonctionne pas si le tuyau en amont n'a rien de sortie ..
clarkttfu
0

Fonctionne également:

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

Générera des chaînes comme:

string 000
string 001
string 002
string 003
string 004

...

cy8g3n
la source