Что именно <() в bash (и = () в zsh)?
Мне довольно комфортно с bash, но недавно я попал на замену, которую я не знал.
Что именно <(<command>) в баш? Как это по сравнению с =(<command>) в зш?
Я понимаю, что это как-то связано с дескрипторами файлов по умолчанию. В моем компьютере
echo <()
возвращается /proc/self/fd/11Я обнаружил, что это копия сценария STDOUT, но это все еще кажется мне довольно запутанным.
3 ответа
Это называется процессом замещения.
<(list) синтаксис поддерживается обоими, bash а также zsh, Предоставляет способ передать вывод команды (list) к другой команде при использовании канала (|) это невозможно. Например, когда команда просто не поддерживает ввод из STDIN или вам нужен вывод нескольких команд:
diff <(ls dirA) <(ls dirB)
<(list) соединяет выход list с файлом в /dev/fd если поддерживается системой, в противном случае используется именованный канал (FIFO) (который также зависит от поддержки системой; ни в одном руководстве не говорится о том, что происходит, если оба механизма не поддерживаются, предположительно, он прерывается с ошибкой). Имя файла затем передается в качестве аргумента в командной строке.
zsh дополнительно поддерживает =(list) как возможная замена <(list), С =(list) временный файл используется вместо файла в /dev/fd или ФИФО. Может использоваться как замена <(list) если программа должна искать в выводе.
В соответствии с руководством по ZSH могут возникнуть и другие проблемы с тем, как <(list) работает:
=форма полезна как/dev/fdи реализация именованного канала<(...)есть недостатки. В первом случае некоторые программы могут автоматически закрывать дескриптор файла, о котором идет речь, прежде чем проверять файл в командной строке, особенно если это необходимо по соображениям безопасности, например, когда программа запускает setuid. Во втором случае, если программа фактически не открывает файл, подоболочка, пытающаяся читать или записывать в канал, будет (в типичной реализации, в разных операционных системах может иметь разное поведение) блокироваться навсегда и должна быть явно уничтожена., В обоих случаях оболочка фактически предоставляет информацию с использованием канала, поэтому программы, ожидающие lseek (см. Справочную страницуlseek(2)) на файл не будет работать.
Обратите внимание, это ответ Bash, а не Zsh.
В bash есть случаи, когда вы не можете использовать трубы:
some_command | some_other_command
Поскольку каналы вводят подоболочки для каждого компонента конвейера, при выходе из подоболочек любые побочные эффекты, на которые вы полагались, исчезли бы. Например, этот надуманный пример:
cat file | while read line; do ((count++)); done
echo $count
будет отображать пустую строку, потому что $count переменная не существует в текущей оболочке.
Подстановка процесса bash позволяет вам избежать этой загадки, позволяя вам читать из вывода "some_command", как если бы вы были из файла
while read line; do ((count++)); done < <(cat file)
# ....................................1.2
echo $count # the variable *does* exist in the current shell
(1) - нормальное перенаправление ввода. (2) это начало <() Синтаксис процесса замены.
Еще одно различие между=(command)&<(command)в zsh синхронное и асинхронное выполнение:
date & \
diff =(sleep 4; date) =(sleep 5; date) & \
diff <(sleep 4; date) <(sleep 5; date) &
Sun 29 Nov 2020 08:16:01 AEDT
[1] 41717 done date
$ 1c1
< Sun 29 Nov 2020 08:16:05 AEDT
---
> Sun 29 Nov 2020 08:16:06 AEDT
[3] + 41719 exit 1 diff <(sleep 4; date) <(sleep 5; date)
$ 1c1
< Sun 29 Nov 2020 08:16:05 AEDT
---
> Sun 29 Nov 2020 08:16:10 AEDT
[2] + 41718 exit 1 diff =(sleep 4; date) =(sleep 5; date)
... хотя понятия не имею, было ли это задумано или нет, поскольку я не могу придумать веской причины для этого=()функционировать синхронно.