Почему `sort <(ls -l)` работает, но `sort <(ls -l)` не работает?

32

Сегодня я узнаю кое-что о fifo в этой статье: Введение в именованные каналы , в которой упоминается cat <(ls -l).

Я сделал несколько экспериментов с использованием sort < (ls -l), которое выскакивает ошибка:

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

Затем я обнаружил, что неправильно ввел лишний пробел в команде.

Но почему эта дополнительная команда приведет к этому провалу? Почему символ перенаправления должен быть близко к (?

Zen
источник
Следует отметить, что * nix shell разделяет вещи на основе пробелов, которые создают токены, упомянутые Алеком.
цыплята

Ответы:

45

Потому что это не <, это <()совершенно другое. Это называется заменой процесса , это особенность определенных оболочек, которая позволяет использовать выходные данные одного процесса в качестве входных данных для другого.

Операторы >и <перенаправляют вывод и ввод из файлов . <()Оператор имеет дело с командами (процессы), а не файлы. Когда ты бежишь

sort < (ls)

Вы пытаетесь выполнить команду lsв подоболочке (это означает, что в скобках), а затем передать эту подоболочку в качестве входного файла sort. Это, однако, неприемлемый синтаксис, и вы получите ошибку, которую вы видели.

Тердон
источник
3
Ваш ответ хороший, но then sort is attempting to read the subshell as its input file→ это, очевидно, неправильно, поскольку Bash даже не будет анализировать синтаксис. Ни на самом деле lsни sortбеги.
Sleblanc
1
@sebleblanc справедливо, перефразировал ответ, спасибо.
Terdon
1
Там нет суб-оболочки в этом случае. < (ls)здесь недействительный токен
Cuonglm
@cuonglm нет, потому что bash воспринимает это как синтаксическую ошибку. Моя точка зрения заключается в том, что (ls)будет работать lsв подоболочке.
Тердон
22

Потому что так и должно быть.

<(...)в bashэто синтаксис для замены процесса. Он скопирован с того же оператора в ksh.

<, (, ), |, &, ;Специальные лексические маркеры в bashкоторые используются для формирования специальных операторов в различных комбинациях. <, <(, <<, <&... каждый имеет свою роль. <для перенаправления. <file, < fileперенаправил бы ввод из файла. <'(file)'будет перенаправлять ввод из файла с именем (file), но <(file)это другой оператор, который не является оператором перенаправления.

< (file)будет <затем (file). В этом контексте, в bash, (file)не является действительным. (...)может быть действительным как один токен в некоторых контекстах, таких как:

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

Но не в

sort < (cmd)

В fishоболочке все по-другому. В fish, (...)для подстановки команд (эквивалент $(...)в bash). И <для перенаправления ввода, как в Bourne-подобных оболочках.

Итак, в fish:

sort <(echo file)

будет так же, как:

sort < (echo file)

То есть:

sort < file

Но это нечто совершенно отличное от bashпроцесса замещения в России.

В yashоболочке, другая оболочка POSIX, <(...)предназначена не для замены процесса, а для перенаправления процесса

Там,

sort <(ls -l)

Короче для:

sort 0<(ls -l)

является оператором перенаправления. Это более или менее эквивалентно:

ls -l | sort

Находясь внутри bash, <(ls -l)он расширяется до пути трубы, так что это больше похоже на:

ls -l | sort /dev/fd/0

В zsh, (...)перегружен как оператор глобинга ( (*.txt|*.png)будет расширяться до txtи pngфайлы) и как спецификатор глобуса ( *(/)например, расширяется до файлов каталога).

В zsh, в:

sort < (ls -l)

Это (ls -l)будет рассматриваться как глобус квалификатор. lГлоб классификатор должен соответствовать по количеству ссылок и ожидает , что число после l(как ls -ld ./*(l2)бы список файлов с 2 ссылки), так вот почему вы получите zsh: number expectedошибку там.

sort < (w)дал бы zsh: no matches found: (w)ошибку вместо того, чтобы, как (w)спички файлы с пустым именем, которые записываемые.

sort < (w|cat)отсортировал бы содержимое файлов wи / или catв текущем каталоге ...

Стефан Шазелас
источник
почему sort < $(ls -l)выдает такую ​​ошибку:bash: $(ls -l): ambiguous redirect
Эдвард Торвальдс
@edwardtorvalds, потому что $(ls -l)расширяется до более чем одного слова. Используйте кавычки, чтобы предотвратить split + glob ( sort < "$(echo file)"). Обратите внимание, что поведение или bashотличается от POSIX sh в этом bash делает это split + glob там, когда он неинтерактивен (не когда вызывается так, как shесли бы).
Стефан Шазелас
глядя на это, ls -l | sort /dev/fd/0я могу сказать, что выходные данные ls -lхранятся в, /dev/fd/0а sortкоманда читает их, чтобы получить желаемый результат. Я использую tail -f --retry /dev/fd/0для мониторинга этого файла, но я не получаю никакого вывода. Зачем? как я могу прочитать этот файл?
Эдвард Торвальдс
В рыбе вы можете использовать (foo | psub)для достижения замены процесса ввода; пока нет замены (га) для замены процесса вывода.
Занчей