Jaka jest różnica między <<
, <<<
a < <
w bash?
command-line
bash
redirect
Searene
źródło
źródło
Odpowiedzi:
Tutaj dokument
<<
jest znany jakohere-document
struktura. Dajesz programowi znać, co będzie końcowym tekstem, i za każdym razem, gdy zobaczysz ten ogranicznik, program odczyta wszystkie dane, które przekazałeś programowi jako dane wejściowe, i wykona na nim zadanie.Oto co mam na myśli:
W tym przykładzie mówimy
wc
programowi, aby czekał naEOF
ciąg znaków, a następnie wpisz pięć słów, a następnie wpisz,EOF
aby zasygnalizować, że wprowadzono dane wejściowe. W rzeczywistości jest podobny do bieganiawc
samemu, wpisywania słów, a następnie naciskaniaCtrlDW bash są one implementowane za pomocą plików tymczasowych, zwykle w formie
/tmp/sh-thd.<random string>
, natomiast w dash są implementowane jako anonimowe potoki. Można to zaobserwować poprzez śledzenie wywołań systemowych za pomocąstrace
polecenia. Wymieńbash
sięsh
, aby zobaczyć, jak/bin/sh
wykonuje to przekierowanie.Tutaj ciąg
<<<
jest znany jakohere-string
. Zamiast wpisywać tekst, podajesz programowi gotowy ciąg tekstu. Na przykład przy takim programie,bc
jaki możemy zrobić,bc <<< 5*4
aby uzyskać dane wyjściowe dla tego konkretnego przypadku, nie trzeba interakcyjnie uruchamiać bc.Tutaj ciągi w bash są implementowane za pomocą plików tymczasowych, zwykle w formacie
/tmp/sh-thd.<random string>
, które później są rozłączane, dzięki czemu zajmują tymczasowo pewną przestrzeń pamięci, ale nie pojawiają się na liście/tmp
pozycji katalogu i skutecznie istnieją jako pliki anonimowe, które mogą nadal odwołuje się do deskryptora pliku przez samą powłokę, a ten deskryptor pliku jest dziedziczony przez polecenie, a następnie powielany na deskryptorze pliku 0 (stdin) przezdup2()
funkcję. Można to zaobserwować poprzezI poprzez śledzenie wywołań systemowych (dane wyjściowe skrócone dla czytelności; zwróć uwagę, jak plik tymczasowy jest otwierany jako fd 3, dane do niego zapisywane, następnie jest ponownie otwierany z
O_RDONLY
flagą jako fd 4, a następnie odłączony, a następniedup2()
na fd 0, który jest dziedziczonycat
później) ):Opinia: potencjalnie ponieważ tutaj łańcuchy wykorzystują tymczasowe pliki tekstowe, jest to możliwy powód, dla którego tutaj łańcuchy zawsze wstawiają końcowy znak nowej linii, ponieważ plik tekstowy według definicji POSIX musi mieć linie kończące się znakiem nowego wiersza.
Zastąpienie procesu
Jak wyjaśnia tldp.org ,
W efekcie jest to podobne do przesyłania potokiem jednego polecenia do drugiego, np
echo foobar barfoo | wc
. Ale zauważ: na stronie bash zobaczysz, że jest oznaczony jako<(list)
. Zasadniczo możesz przekierować dane wyjściowe wielu (!) Poleceń.Uwaga: technicznie rzecz biorąc, gdy mówisz,
< <
że nie masz na myśli jednej rzeczy, ale dwa przekierowania z pojedynczym<
i procesowym przekierowaniem wyjścia z<( . . .)
.Co się stanie, jeśli dokonamy tylko zamiany?
Jak widać, powłoka tworzy tymczasowy deskryptor pliku, do
/dev/fd/63
którego trafia dane wyjściowe (co według odpowiedzi Gillesa jest anonimową potokiem). Oznacza to,<
że przekierowuje ten deskryptor pliku jako dane wejściowe do polecenia.Tak bardzo prostym przykładem może być zamiana procesu podstawiania danych wyjściowych z dwóch poleceń echa na wc:
Więc tutaj zmuszamy powłokę do utworzenia deskryptora pliku dla wszystkich danych wyjściowych w nawiasach i przekierowania, które jako dane wejściowe do
wc
. Jak oczekiwano, wc odbiera ten strumień z dwóch poleceń echa, które same z siebie wyprowadziłyby dwie linie, z których każda zawiera słowo, i odpowiednio mamy 2 słowa, 2 linie i 6 znaków plus dwie nowe linie.Uwaga dodatkowa: Podstawienie procesu może być określane jako bashism (polecenie lub struktura użyteczne w zaawansowanych powłokach takich jak
bash
, ale nie określone przez POSIX), ale zostało zaimplementowaneksh
przed istnieniem basha jako strona podręcznika użytkownika ksh i ta odpowiedź sugeruje. Powłoki jaktcsh
imksh
jednak nie mają substytucji procesu. Jak więc moglibyśmy przekierowywać wyjście wielu poleceń do innego polecenia bez zastępowania procesu? Grupowanie plus orurowanie!W rzeczywistości jest to to samo co w powyższym przykładzie, jednak różni się to pod maską od zastępowania procesu, ponieważ wykonujemy stdout całej podpowłoki i stdin
wc
połączony z rurą . Z drugiej strony podstawienie procesu powoduje, że polecenie czyta tymczasowy deskryptor pliku.Jeśli więc możemy grupować za pomocą pipingu, dlaczego potrzebujemy podstawiania procesów? Ponieważ czasami nie możemy używać rur. Rozważ poniższy przykład - porównanie wyników dwóch poleceń z
diff
(które wymagają dwóch plików, w tym przypadku podajemy dwa deskryptory plików)źródło
< <
jest używany, gdy otrzymuje się standardowe wejście z podstawienia procesu . Takie polecenie może wyglądać tak:cmd1 < <(cmd2)
. Na przykładwc < <(date)
< <
nie jest rzeczą samą w sobie, w przypadku substytucji procesu<
następuje po niej coś innego, co zaczyna się od<
<<<
najpierw został zaimplementowany przez port uniksowy powłoki Plan 9 rc, a następnie przyjęty przez zsh, bash i ksh93. Nie nazwałbym tego bazmem.echo 'foo' | read; echo ${REPLY}
będzie nie powrócifoo
, ponieważread
jest rozpoczynane w podpowłoce - orurowanie rozpoczyna podpowłoce. Jednakread < <(echo 'foo'); echo ${REPLY}
poprawnie zwracafoo
, ponieważ nie ma podpowłoki.< <
jest błędem składni:< <()
to proces podstawiania (<()
) w połączeniu z przekierowaniem (<
):Przemyślany przykład:
W przypadku podstawienia procesu ścieżka do deskryptora pliku jest używana jak nazwa pliku. W przypadku, gdy nie chcesz (lub nie możesz) bezpośrednio użyć nazwy pliku, łączysz podstawienie procesu z przekierowaniem.
Żeby było jasne, nie ma
< <
operatora.źródło
<()
daje nazwę podobną do nazwy pliku, więc jest bardziej użyteczna -< <()
zastępuje stdin tam, gdzie może nie być konieczne. Wwc
tym drugim przypadku okazuje się bardziej przydatne. Może być mniej przydatny gdzie indziej< <
to błąd składniowy, prawdopodobnie masz na myślicommand1 < <( command2 )
proste przekierowanie wejścia, po którym następuje podstawienie procesu i jest bardzo podobne, ale nie równoważne z:Różnica przy założeniu, że działasz,
bash
jestcommand1
uruchamiana w podpowłoce w drugim przypadku, podczas gdy jest uruchamiana w bieżącej powłoce w pierwszym. Oznacza to, że ustawione zmiennecommand1
nie zostaną utracone w wariancie substytucji procesu.źródło
< <
da błąd składniowy. Właściwe użycie jest następujące:Wyjaśnienie za pomocą przykładów:
Przykład dla
< <()
:W powyższym przykładzie dane wejściowe do pętli while będą pochodzić z
ls
polecenia, które można odczytać wiersz po wierszu iecho
edytować w pętli.<()
służy do podstawienia procesu. Więcej informacji i przykład<()
można znaleźć pod tym linkiem:Zastąpienie procesu i rura
źródło