Что именно <() в 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)
... хотя понятия не имею, было ли это задумано или нет, поскольку я не могу придумать веской причины для этого=()
функционировать синхронно.