Dlaczego `sort <(ls -l)` działa, ale `sort <(ls -l)` nie działa?

32

Dzisiaj uczę się czegoś o fifo w tym artykule: Wprowadzenie do nazwanych potoków , o którym wspomniano cat <(ls -l).

Zrobiłem kilka eksperymentów, używając sort < (ls -l), który wyskakuje błąd:

-bash: syntax error near unexpected token `('`

Potem odkryłem, że źle wprowadziłem dodatkowe miejsce w poleceniu.

Ale dlaczego to dodatkowe polecenie doprowadzi do niepowodzenia? Dlaczego symbol przekierowania musi być zbliżony do (?

Zen
źródło
Należy zauważyć, że powłoki * nix dzielą rzeczy na podstawie białych znaków, które tworzą tokeny wspomniane przez Aleca.
pisklęta

Odpowiedzi:

45

Ponieważ to nie jest <, to jest coś <()zupełnie innego. Nazywa się to substytucją procesu , jest to funkcja niektórych powłok, która pozwala wykorzystać dane wyjściowe jednego procesu jako dane wejściowe dla innego.

>I <operatorzy przekierować wyjście do i wejście z plikami . <()Operator zajmuje polecenia (procesów), a nie pliki. Kiedy biegniesz

sort < (ls)

Próbujesz uruchomić polecenie lsw podpowłoce (co oznaczają nawiasy), a następnie przekazać tę podpowłokę jako plik wejściowy sort. Nie jest to jednak akceptowana składnia i pojawia się wyświetlony błąd.

terdon
źródło
3
Twoja odpowiedź jest dobra, ale then sort is attempting to read the subshell as its input file→ jest to oczywiście błędna, ponieważ Bash nawet nie przeanalizuje składni. Ani lsnie sortjest uruchomiony.
sleblanc
1
@sebleblanc fair point, przeformułował odpowiedź, dzięki.
terdon
1
W tym przypadku nie ma podpowłoki. < (ls)nie jest tutaj poprawnym tokenem.
cuonglm
@cuonglm nie, ponieważ bash traktuje to jako błąd składniowy. Chodzi mi o to, (ls)że działałoby lsw podpowłoce.
terdon
22

Ponieważ tak ma być.

<(...)in bashto składnia podstawiania procesów. Jest skopiowany od tego samego operatora w ksh.

<, (, ), |, &, ;Są specjalne tokeny leksykalne w bashktóre są stosowane do tworzenia specjalnych operatorów w różnych kombinacjach. <, <(, <<, <&... każdy ma swoją rolę. <służy do przekierowania. <file, < fileprzekieruje dane wejściowe z pliku. <'(file)'przekieruje dane wejściowe z pliku o nazwie (file), ale <(file)jest innym operatorem, który nie jest operatorem przekierowania.

< (file)będzie <następnie (file). W tym kontekście, w bash, (file)nie jest ważny. (...)może być poprawny jako pojedynczy token w niektórych kontekstach, takich jak:

(sub shell)
func () {
  ...
}
var=(foo bar)

Ale nie w

sort < (cmd)

W fishpowłoce jest inaczej. W fish, (...)jest podstawienie poleceń (równowartość $(...)w bash). I <służy do przekierowywania danych wejściowych jak w powłokach podobnych do Bourne'a.

Więc w fish:

sort <(echo file)

byłby taki sam jak:

sort < (echo file)

To jest:

sort < file

Ale to coś zupełnie innego niż bashpodstawianie procesów.

W yashpowłoce kolejna powłoka POSIX <(...)nie służy do zastępowania procesów, ale do przekierowywania procesów

Tam,

sort <(ls -l)

Skrót od:

sort 0<(ls -l)

jest operatorem przekierowania. Jest to mniej więcej odpowiednik:

ls -l | sort

Podczas bashgdy <(ls -l)jest rozwinięty do ścieżki potoku, więc bardziej przypomina:

ls -l | sort /dev/fd/0

W zsh, (...)jest przeciążony jako operator globowania ( (*.txt|*.png)rozwinie się txti pngpliki) i jako kwalifikator glob ( *(/)na przykład rozszerza się do plików, katalogów).

W zsh: w:

sort < (ls -l)

To (ls -l)byłoby traktowane jako kwalifikator globalny. lGlob kwalifikator jest dopasowanie na liczbie linków i oczekuje wiele po l(jak ls -ld ./*(l2)by wyświetlić listę plików z 2 linków), więc to dlaczego masz zsh: number expectedbłąd istnieje.

sort < (w)dałby zsh: no matches found: (w)błąd zamiast jako (w)meczów pliki z pustą nazwą, które są zapisu.

sort < (w|cat)posortowałby zawartość plików wi / lub catplików w bieżącym katalogu ...

Stéphane Chazelas
źródło
dlaczego sort < $(ls -l)podaje ten błąd:bash: $(ls -l): ambiguous redirect
Edward Torvalds,
@edwardtorvalds, ponieważ $(ls -l)rozwija się do więcej niż jednego słowa. Użyj cudzysłowów, aby zapobiec split + glob ( sort < "$(echo file)"). Zauważ, że zachowanie lub bashróżniące się od POSIX sh w tym bashu robi to split + glob również tam, gdy nie jest interaktywny (nie kiedy jest wywoływany tak, shjakby).
Stéphane Chazelas,
patrząc na ls -l | sort /dev/fd/0mogę powiedzieć, że dane wyjściowe ls -lsą przechowywane /dev/fd/0i sortpolecenie odczytuje je, aby uzyskać pożądany wynik. Używam tail -f --retry /dev/fd/0do monitorowania tego pliku, ale nie otrzymuję żadnych danych wyjściowych. czemu? jak mogę odczytać ten plik?
Edward Torvalds,
U ryb można użyć (foo | psub)do osiągnięcia substytucji procesu wejściowego; nie ma jeszcze substytutu (ha) dla substytucji procesu wyjściowego.
Zanchey