Jak połączyć stdin i string?


108

Jak połączyć stdin z łańcuchem, w ten sposób?

echo "input" | COMMAND "string"

i dostać

inputstring

Odpowiedzi:


119

Trochę hacky, ale może to być najkrótszy sposób na zrobienie tego, o co pytałeś w pytaniu (użyj potoku, aby zaakceptować stdoutod echo "input"jako stdindo innego procesu / polecenia:

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

Wynik:

inputstring

Jakie zadanie dokładnie próbujesz wykonać? Więcej kontekstu może dać ci więcej wskazówek co do lepszego rozwiązania.

Aktualizacja - odpowiadanie na komentarz:

@NoamRoss

Bardziej idiomatyczny sposób robienia tego, co chcesz, to:

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

$(...)Składni nazywa zastąpienie polecenia . Krótko mówiąc, wykonuje polecenia zawarte w nowej podpowłoce i zastępuje swoje stdoutdane wyjściowe miejscem, w którym $(...)została wywołana w powłoce nadrzędnej. W efekcie otrzymujesz:

echo 'http://dx.doi.org/'"rsif.2012.0125"

1
Dzięki! To działa świetnie. Dokładnym zadaniem, które próbuję wykonać, jest pobranie ciągu ze schowka (DOI) i dołączenie do niego adresu URL, więc robię to pbpaste | awk '{print "http://dx.doi.org/"$1}'i otrzymujęhttp://dx.doi.org/10.1098/rsif.2012.0125
Noam Ross

5
@ sampson-chen, użyłbym '{print $0"string"}'do złapania całości.
Roman Newaza

3
W rzeczywistości dołącza się stringdo każdej linii. Spróbuj echo 'input'\n'another line' | awk '{print $0"string"}'.
tomekwi

55

użyj cat -do czytania ze standardowego wejścia i wstaw go, $()aby pozbyć się końcowego znaku nowej linii

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

Jednak dlaczego nie upuścisz potoku i nie złapiesz wyjścia z lewej strony w zamianie poleceń:

COMMAND "$(echo input)string"

1
Oto praktyczny przykład: find ~ / other_program / lib -name "* .jar" | tr '\ n' ':' | echo "$ (cat -) ~ / java_app / classes"
Ashwin Jayaprakash

2
To działa dla mnie w bash, ale w zsh otrzymuję "cat: -: Błąd wejścia / wyjścia". Każdy pomysł, co może to spowodować?
jaymmer - Przywróć Monikę

„POLECENIE” oznacza rozwiązanie, a „wejście echa” oznacza bardziej skomplikowany proces. Argument "-" do cat jest wymagany tylko wtedy, gdy istnieją inne argumenty pliku, w przeciwnym razie jest domyślny. Więc miałeś na myśli: wejście echa | echo $ (cat) string
Denis Howe

46

Często używam potoków, więc zwykle jest to łatwy sposób na prefiks i sufiks stdin:

echo -n "my standard in" | cat <(echo -n "prefix... ") - <(echo " ...suffix")
prefix... my standard in ...suffix

2
Dzięki! To naprawdę fajny przykład użycia pipeicat
Alex Ivasyuv

1
To powinna być najlepsza odpowiedź
Chris Koston

1
Dlaczego nie tylko echo "my standard in" | echo -e "prefix\n$(cat -)\nsuffix":? Lub bardziej czytelna wersja:echo "my standard in" | printf "%s\n%s\n%s\n" "prefix" "$(cat -)" "suffix"
MiniMax

1
@MiniMax Ponieważ odpowiedź działa dobrze w przypadku strumieni, będzie działać dla dużego standardowego wejścia.
anishpatel

1
@anishpatel Moja wersja będzie działać również z dużym stdin. Bez różnicy.
MiniMax

11

Możesz to zrobić za pomocą seda:

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

W twoim przykładzie:

echo input | sed 's/.*/\0string/'

9

Jest na to kilka sposobów, osobiście uważam, że najlepszym jest:

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

Innym sposobem może być zastąpienie „$” (znak końca wiersza) ciągiem w poleceniu sed:

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

Dlaczego wolę to pierwsze? Ponieważ natychmiast łączy ciąg na stdin, na przykład za pomocą następującego polecenia:

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

natychmiast otrzymasz pierwszy wynik:

input_one string

a następnie po 5 sekundach pojawi się drugie echo:

input_two string

Z drugiej strony, używając „sed” najpierw wykonuje całą zawartość nawiasu, a następnie przekazuje ją „sed”, więc polecenie

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

wyświetli obie linie

input_one string
input_two string

po 5 sekundach.

Może to być bardzo przydatne w przypadkach, gdy wykonujesz wywołania funkcji, których wykonanie zajmuje dużo czasu i chcesz być na bieżąco aktualizowany o wynikach funkcji.


W rzeczywistości opcja sed również natychmiast przetwarza każdy wiersz danych wejściowych.
tomekwi

Dla pojedynczej linii wejściowej najprostszym rozwiązaniem jest wejście echa | (przeczytaj v; echo $ {v} string) To czysta powłoka, więc nie wymaga dodatkowego procesu, takiego jak sed.
Denis Howe

7

Wiem, że to opóźnienie o kilka lat, ale możesz to osiągnąć za pomocą opcji xargs -J:

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

A ponieważ jest to xargs, możesz to zrobić w wielu wierszach pliku jednocześnie. Jeśli plik „names” ma trzy linie, na przykład:

Adam
Bob
Charlie

Mógłbyś:

cat names | xargs -n 1 -J "%" echo "I like" "%" "because he is nice"

1
Wygląda fajnie, z wyjątkiem tego, -Jże nie wydaje się być standardowy / powszechny. W systemie Linux (gdzie xargsjest część GNU findutils) pojawia się błąd: w xargs: invalid option -- 'J'którym systemie to działa?
arielf

3
-Jdotyczy wersji na komputery Mac. W przypadku Linuksa -Ipełni tę samą funkcję.
user2635263

1
Dzięki! bardzo przydatne. Proszę zauważyć, że w Linuksie ta uproszczona wersja działa równie dobrze: cat names | xargs -I% echo "I like % because he is nice"IOW: nie ma potrzeby -n 1( xargswywołania echoraz na wiersz wejścia i tak, ponieważ -Iimplikuje -L1). Ponadto, wszystkie oddzielne cytowania argumentów wydają się zbędne.
arielf

3

Polecenie, które wysłałeś, użyłoby łańcucha „input” jako strumienia wejścia standardowego COMMAND, co nie dałoby wyników, których szukasz, chyba że COMMAND najpierw wydrukowałby zawartość swojego wejścia standardowego, a następnie wypisał argumenty wiersza poleceń.

Wygląda na to, że to, co chcesz zrobić, jest bardziej zbliżone do zastępowania poleceń.

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

Dzięki podstawianiu poleceń możesz mieć taką linię poleceń:

echo input `COMMAND "string"`

Spowoduje to najpierw oszacowanie polecenia COMMAND z "ciągiem" jako danymi wejściowymi, a następnie rozszerzenie wyników wykonania tego polecenia na wiersz, zastępując to, co znajduje się między znakami '`'.


i oczywiście @NaomRoss, chyba że musisz używać powłoki Bourne'a lub masz inne szalone mandaty „przenośności”, użyjesz nowoczesnego zastępowania poleceń echo input $(COMMAND "string"), a nie odwrotnych apostrofów. Powodzenia wszystkim.
łowca

1

kot będzie moim wyborem: ls | cat - <(echo new line)


sed to polecenie oparte na linii, które nie działa, jeśli potok wyjściowy nie ma żadnego wyjścia ..
clarkttfu

0

Działa również:

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

Wygeneruje ciągi takie jak:

string 000
string 001
string 002
string 003
string 004

...

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.