Wyślij ciąg na stdin

158

Czy istnieje sposób, aby skutecznie to zrobić w bash:

/my/bash/script < echo 'This string will be sent to stdin.'

Zdaję sobie sprawę, że mogę potokować wyjście z echa, takie jak to:

echo 'This string will be piped to stdin.' | /my/bash/script
Wszyscy pracownicy są niezbędni
źródło
1
Co masz na myśli mówiąc efektywnie , dlaczego fajka nie jest sposobem na zrobienie tego?
Andy
Oba wymienione polecenia powinny robić dokładnie to samo. Jaki masz problem?
Flimzy
5
@Flimzy: afaik, pierwszy nie zadziała zgodnie z oczekiwaniami, spróbuje otworzyć plik o nazwieecho
Andy
No tak. Więc co jest nie tak z drugą formą?
Flimzy
2
@Flimzy: poza tym >formularz przekierowania otworzy deskryptor pliku jako fd 0(stdin), podczas gdy |opens uruchamia proces potomny i dołącza jego standardowe wyjście (fd 1) do wejścia standardowego innego procesu. Fakt ten może mieć niebanalną konsekwencje (pomyśl o dzielenie zmiennych środowiskowych?)
sehe

Odpowiedzi:

262

Możesz użyć jednej linii heredoc

cat <<< "This is coming from the stdin"

powyższe jest takie samo jak

cat <<EOF
This is coming from the stdin
EOF

lub możesz przekierować dane wyjściowe z polecenia, na przykład

diff <(ls /bin) <(ls /usr/bin)

lub możesz przeczytać jako

while read line
do
   echo =$line=
done < some_file

lub po prostu

echo something | read param
jm666
źródło
A jak w ten sposób wprowadzać wartości binarne? Bez korzystania z potoku (wiem, można to zrobić z rurą w następujący sposób: echo -e "\x01\x02..." | ./script)
cprcrack
Lubię to pisać w inny sposób: <<< "To pochodzi ze stdin" perl ..., w ten sposób wygląda jak lewa strona rury.
Pyrolistic
@Pirolistic tak! Szczególnie przydatne przy opanowywaniu np. Onelinera perla z linii poleceń - łatwa edycja argumentów perla bez konieczności wykonywania wielu ruchów wstecz kursorem. :)
jm666
@ jm666 smutną rzeczą jest to, że nauczyłem się wczoraj, jeśli używasz aliasu bash, po prostu używasz formularza command_alias <<< "ciąg stdin", w przeciwnym razie powie polecenie nie znaleziono
pirolistyczne
@ jm666 Czy jest miejsce, o którym mogę dowiedzieć się więcej <<<? Wstydzę się przyznać, że nigdy wcześniej go nie widziałem i jestem tym totalnie zaintrygowany. Próbowałem googlować, ale moje wyniki nie były powiązane.
wpcarro
66

Byłeś blisko

/my/bash/script <<< 'This string will be sent to stdin.'

W przypadku wejścia wielowierszowego odpowiednie są dokumenty tutaj:

/my/bash/script <<STDIN -o other --options
line 1
line 2
STDIN

Edytuj komentarze:

Powiedzmy, aby uzyskać wejście binarne

xxd -r -p <<BINARY | iconv -f UCS-4BE -t UTF-8 | /my/bash/script
0000 79c1 0000 306f 0000 3061 0000 3093 0000 3077 0000 3093 0000 304b 0000 3093 0000 3077 0000 3093 0000 306a 0000 8a71 0000 306b 0000 30ca 0000 30f3 0000 30bb
0000 30f3 0000 30b9 0000 3092 0000 7ffb 0000 8a33 0000 3059 0000 308b 0000 3053 0000 3068 0000 304c 0000 3067 0000 304d 0000 000a
BINARY

Jeśli zastąpić catna /my/bash/script(lub faktycznie spaść ostatnią rurę), to drukuje:

私はちんぷんかんぷんな話にナンセンスを翻訳することができ

Lub, jeśli chcesz czegoś bardziej naukowego:

0000000: 0000 0000 bef9 0e3c 59f8 8e3c 0a71 d63c  .......<Y..<.q.<
0000010: c6f2 0e3d 3eaa 323d 3a5e 563d 090e 7a3d  ...=>.2=:^V=..z=
0000020: 7bdc 8e3d 2aaf a03d b67e b23d c74a c43d  {..=*..=.~.=.J.=
0000030: 0513 d63d 16d7 e73d a296 f93d a8a8 053e  ...=...=...=...>
0000040: 6583 0e3e 5a5b 173e 5b30 203e 3d02 293e  e..>Z[.>[0 >=.)>
0000050: d4d0 313e f39b 3a3e 6f63 433e 1c27 4c3e  ..1>..:>ocC>.'L>
0000060: cde6 543e 59a2 5d3e 9259 663e 4d0c 6f3e  ..T>Y.]>.Yf>M.o>
0000070: 60ba 773e cf31 803e ee83 843e 78d3 883e  `.w>.1.>...>x..>
0000080: 5720 8d3e 766a 913e beb1 953e 1cf6 993e  W .>vj.>...>...>
0000090: 7a37 9e3e c275 a23e dfb0 a63e bce8 aa3e  z7.>.u.>...>...>
00000a0: 441d af3e 624e b33e 017c b73e 0ca6 bb3e  D..>bN.>.|.>...>
00000b0: 6fcc bf3e 15ef c33e e90d c83e d728 cc3e  o..>...>...>.(.>
00000c0: c93f d03e ac52 d43e 6c61 d83e f36b dc3e  .?.>.R.>la.>.k.>
00000d0: 2f72 e03e 0a74 e43e 7171 e83e 506a ec3e  /r.>.t.>qq.>Pj.>
00000e0: 945e f03e 274e f43e f738 f83e f11e fc3e  .^.>'N.>.8.>...>
00000f0: 0000 003f 09ee 013f 89d9 033f 77c2 053f  ...?...?...?w..?
0000100: caa8 073f 788c 093f 776d 0b3f be4b 0d3f  ...?x..?wm.?.K.?
0000110: 4427 0f3f 0000 113f e8d5 123f f3a8 143f  D'.?...?...?...?
0000120: 1879 163f 4e46 183f 8d10 1a3f cad7 1b3f  .y.?NF.?...?...?
0000130: fe9b 1d3f 1f5d 1f3f 241b 213f 06d6 223f  ...?.].?$.!?.."?
0000140: bb8d 243f 3a42 263f 7cf3 273f 78a1 293f  ..$?:B&?|.'?x.)?
0000150: 254c 2b3f 7bf3 2c3f 7297 2e3f 0138 303f  %L+?{.,?r..?.80?
0000160: 22d5 313f ca6e 333f                      ".1?.n3?

Który jest sinusem pierwszych 90 stopni w 4-bajtowych liczbach zmiennoprzecinkowych

sehe
źródło
A jak w ten sposób wprowadzać wartości binarne?
cprcrack
Użyłbym xxd -r(lub od), aby filtrować tu dokument
sehe
Czy mógłbyś to wyjaśnić na przykładzie? Nie udało mi się to zrobić.
cprcrack
1
zobacz zredagowaną odpowiedź. Chodzi o to, aby nie obejmują surowych danych binarnych w skrypcie, ale zamiast filtrować je za pomocą programu jak xxd
sehe
Jaki jest sens zrobienia: "/ my / bash / script <<< 'Ten ciąg zostanie wysłany na stdin.'" Kiedy możesz bezpośrednio powiedzieć: "/ my / bash / script 'Ten ciąg zostanie wysłany na stdin. '"?
Baiyan Huang
2

Możesz także użyć w readten sposób

echo "enter your name"
read name
echo $name
Rahul
źródło
2

Rozwiązanie

Chcesz (1) utworzyć wyjście stdout w jednym procesie (jak echo '…') i (2) przekierować to wyjście na wejście stdin innego procesu, ale (3) bez użycia mechanizmu potoku bash. Oto rozwiązanie spełniające wszystkie trzy warunki:

/my/bash/script < <(echo 'This string will be sent to stdin.')

Jest <to normalne przekierowanie wejścia dla wejścia standardowego. Jest <(…)to podstawienie procesu bash. Z grubsza tworzy /dev/fd/…plik z wyjściem polecenia podstawiania i przekazuje tę nazwę pliku zamiast <(…), co daje na przykład script < /dev/fd/123. Aby uzyskać szczegółowe informacje, zobacz tę odpowiedź

Porównanie z innymi rozwiązaniami

  • Jednowierszowy heredoc wysyłany do stdin script <<< 'string'pozwala tylko na wysyłanie statycznych łańcuchów, a nie na wyjście innych poleceń.

  • Samo podstawianie procesu, na przykład in diff <(ls /bin) <(ls /usr/bin), nie wysyła niczego na stdin. Zamiast tego dane wyjściowe procesu są przekazywane jako zawartość plików tworzonych w tle, równoważne na przykład diff /dev/fd/10 /dev/fd/11. W tym poleceniu diffnie pobiera danych wejściowych ze standardowego wejścia.

Przypadków użycia

Podoba mi się to, w przeciwieństwie do mechanizmu rurowego, < <(…) mechanizm pozwala na umieszczenie polecenia na pierwszym miejscu, a wszystkie dane wejściowe po nim, tak jak jest to standard dla danych wejściowych z opcji wiersza poleceń.

Jednak poza estetyką wiersza poleceń istnieją przypadki, w których nie można zastosować mechanizmu rurowego. Na przykład, gdy określone polecenie musi zostać podane jako argument do innego polecenia, tak jak w tym przykładzie zsshpass .

tanius
źródło
Ciekawa alternatywa. Czy jest to zgodne z POSIX w przeciwieństwie do <<<?
Wszyscy pracownicy są niezbędni
0
cat | /my/bash/script

Umożliwia wpisanie wielu wierszy do programu bez zapisywania tych danych wejściowych w historii ani widocznych w ps. Aby zakończyć pisanie, po prostu naciśnij Ctrl + C po zakończeniu pisania cat.

Walf
źródło
-1

aliasy mogą i nie mogą przetwarzać standardowego wejścia potokowego ...

Tutaj tworzymy 3 linie wyjścia

$ echo -e "line 1\nline 2\nline 3"
line 1
line 2
line 3

Następnie przesyłamy wyjście potokiem do stdin polecenia sed, aby umieścić je wszystkie w jednym wierszu

$ echo -e "line 1\nline 2\nline 3" |  sed -e ":a;N;\$!ba ;s?\n? ?g"
line 1 line 2 line 3

Jeśli zdefiniujemy alias tego samego polecenia sed

$ alias oline='sed -e ":a;N;\$!ba ;s?\n? ?g"'

Możemy potokować wyjście do stdin aliasu i zachowuje się dokładnie tak samo

$ echo -e "line 1\nline 2\nline 3" |  oline
line 1 line 2 line 3

Problem pojawia się, gdy próbujemy zdefiniować alias jako funkcję

$ alias oline='function _oline(){ sed -e ":a;N;\$!ba ;s?\n? ?g";}_oline'

Zdefiniowanie aliasu jako funkcji zrywa potok

$ echo -e "line 1\nline 2\nline 3" |  oline
>
KenB
źródło
Po pierwsze, to nie odpowiada na pytanie - może odpowiedziałeś na złe pytanie? Po drugie, dlaczego miałbyś kiedykolwiek definiować funkcję w aliasie? Po prostu powinieneś to zrobić function oline() { sed -e ":a;N;\$!ba ;s?\n? ?g"; }. Po trzecie, ten sed byłby o wiele bardziej zrozumiały z awk:awk -F '\n' 'ORS=" " { print } END { printf "\n"}'
Leonardo Dagnino