Почему подстановка процесса приводит к файлу / dev / fd / 63, представляющему собой канал?

40

Я пытаюсь понять именованные каналы в контексте этого конкретного примера.

Я печатаю <(ls -l)в своем терминале и получаю вывод как bash: /dev/fd/63: Permission denied.

Если я наберу cat <(ls -l), я мог видеть содержимое каталога. Если я заменить catс echo, я думаю , что я получаю имя терминала (или это?).

echo <(ls -l)дает вывод как /dev/fd/63.

Кроме того, этот пример вывода неясен для меня.

ls -l <(echo "Whatever")
lr-x------ 1 root root 64 Sep 17 13:18 /dev/fd/63 -> pipe:[48078752]

Однако, если я дам, ls -l <()он перечисляет мне содержимое каталога.

Что происходит в случае именованной трубы?

Рамеш
источник

Ответы:

37

Когда вы это сделаете <(some_command), ваша оболочка выполнит команду внутри скобок и заменит все это дескриптором файла, который подключен к стандартному выводу команды. Как /dev/fd/63и канал, содержащий выходные данные вашего вызова ls.

Когда вы <(ls -l)получаете сообщение Permission deniedоб ошибке, потому что вся строка заменяется на канал, эффективно пытаясь вызвать /dev/fd/63как команду, которая не является исполняемой.

В вашем втором примере cat <(ls -l)становится cat /dev/fd/63. Когда cat читает файлы, заданные в качестве параметров, вы получаете содержимое. echoс другой стороны, просто выводит свои параметры «как есть».

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

Сводка : <(command)позволяет вам использовать вывод команды, где вам обычно требуется файл.

Редактировать: как указывает Жиль , это не именованный канал, а анонимный канал. Основное отличие состоит в том, что он существует только до тех пор, пока процесс запущен, а именованный канал (созданный, например, с помощью mkfifo) останется без прикрепленных к нему процессов.

crater2150
источник
5
mkfifoсоздает только именованный канал без содержимого. Так что вам нужно написать это самостоятельно (например mkfifo mypipe; ls > mypipe). И да, записи в канал будут блокироваться до тех пор, пока какой-либо процесс не выполнит чтение из канала.
crater2150
6
Здесь нет именованной трубы. /dev/fd/63это анонимный канал
Жиль "ТАК - перестань быть злым"
1
@ crater2150, @Gilles / dev / fd / 63 действительно именованная труба. Проверьте это с чем-то вроде file <(ls). Оболочка создает анонимный канал, но дескриптор файла отображается как именованный канал в /dev/fd. Если бы это был анонимный канал, он не имел бы имени и не мог бы быть открыт командой, которой /dev/fd/63передается.
с.в.
2
@rv Это все еще анонимный канал. Тот факт, что существует имя файла, которое ссылается на этот анонимный канал, не делает его именованным каналом: именованный канал отличается, он существует где-то в файловой системе, имеет разрешения и владельца и т. Д. Записи /dev/fdмогут относиться к любому файлу дескриптор, даже анонимные каналы и сокеты, сетевые сокеты, сегменты разделяемой памяти и т. д.
Жиль, «Так, перестань быть злым»
1
Почему это 63 , хотя?
K3 --- RNC
-4

Вы неправильно понимаете как lsкоманду, так и перенаправление. lsперечисляет файлы и каталоги, указанные в командной строке, я не верю, что он принимает какие-либо входные данные от стандартного ввода. Перенаправление > >>и <способы использования файла для ввода и сбора выходных данных.

rhubarbdog
источник
1
Здесь нет перенаправления из файла. <(…)это замена процесса.
Жиль "ТАК - перестань быть злым"
1
@IMSoP - как сказал Жиль - это не именованный канал - это анонимный канал. Это очень похоже на x|yи почти идентично [num]<<REDIRECTв некоторых оболочках. Отличие заключается в буквальной подстановке оболочки ссылки fd - /dev/fd/63и т. Д. И в том, что она делает - или не делает - с помощью stdin. Сделайте echo | readlink /dev/fd/0и убедитесь сами.
mikeserv
1
@IMSoP - это devссылка - специальный файл. Вы можете сделать то же самое с любым файловым дескриптором в большинстве систем Linux - даже типично |pipes, хотя я не ручаюсь за поведение в другом месте. я понимаю, откуда вы, но именованный канал - это отдельная вещь для себя - это ссылка файловой системы на канал в ядре - обычная ссылка на файловую систему, а не файл устройства.
mikeserv
1
@mikeserv Интересно, что руководство Bash упоминает, что оно будет работать в системах без /dev/fd/*создания именованного канала где-то еще. Но я понимаю, что /dev/fd/*сам по себе механизм отличается от собственно именованного канала. Кстати, описание Википедии может быть связано с объяснением этого различия.
IMSoP
1
@mikeserv Согласно другим ссылкам, которые я нашел, это проще, чем: если /dev/fd/*не доступно, bash создаст именованный канал /tmpи использует его для подстановки процесса. Мне это не кажется странным, просто сделать функционал доступным в максимально возможном количестве сред.
IMSoP