Почему подстановка процесса BASH не работает с некоторыми командами?

29

В некоторых случаях процесс замены не будет работать должным образом. Вот пример:

Входные данные:

gcc <(echo 'int main(){return 0;}')

Выход:

/dev/fd/63: file not recognized: Illegal seek
collect2: error: ld returned 1 exit status

Входные данные:

Но он работает, как и ожидалось, когда используется с другой командой:

grep main <(echo 'int main(){return 0;}')

Выход:

int main(){return 0;}

Я заметил подобные сбои с другими командами (то есть команда, ожидающая файл от подстановки процесса, не может использоваться /dev/fd/63или подобна). Этот сбой gccтолько самый последний. Есть ли какое-то общее правило, о котором я должен знать, чтобы определить, когда подстановка процесса потерпит неудачу и не должна использоваться?

Я использую эту версию BASH в Ubuntu 12.04 (я также видел это в arch и debian):
GNU bash, версия 4.3.11 (1) -релиз (i686-pc-linux-gnu)

Lotney
источник
1
illegal seekвыглядит как ответ - |pipeэто bashуказывает на то, что исполняемая программа не является доступным для поиска файлом. вероятно, если вы не можете успешно echo data | command /dev/fd/0в программе, то вам повезет с / <(cmd). Он не предоставляет файл на диске - он просто заменяет аргумент, который указывает на дескриптор файла канала.
mikeserv
2
В этом конкретном случае, хотя gcc может принимать стандартный ввод, он (по умолчанию) использует расширение имени файла для определения языка. Так что попробуйте gcc -xc <(echo 'int main(){return 0;}')(который устанавливает язык Cявно).
SteelDriver
Я был направлен сюда в ответ на мой собственный вопрос, который, вероятно, является еще одним примером этого. superuser.com/questions/1243405 . Спасибо, что сформулировал вопрос лучше, чем я смог.
Джонатан Хартли

Ответы:

33

Подстановка процесса приводит к специальному файлу (как /dev/fd/63в вашем примере), который ведет себя как конец чтения именованного канала. Этот файл можно открывать и читать, но не писать, не искать.

Команды, которые рассматривают свои аргументы как чистые потоки, работают, в то время как команды, которые ожидают искать в файлах, которые им дают (или записывают в них), не будут работать. Вид команды , которая будет работать то , что обычно считается фильтр cat, grep, sed, gzip, awkи т.д. ... Пример команды , которая не будет работать является редактором , как viи операция файл как mv.

gccхочет иметь возможность произвольного доступа к своим входным файлам, чтобы определить, на каком языке они написаны. Если вместо этого вы дадите gccподсказку о языке входного файла, он будет рад передать файл:

gcc -x c <(echo 'int main(){return 0;}')

Более простая, более простая форма без подстановки процесса также работает:

echo 'int main(){return 0;}' | gcc -x c -

Обратите внимание, что это не относится к bash. Все оболочки, поддерживающие процесс замены, ведут себя одинаково.

Celada
источник
+1 за обходной путь gcc, но я не уверен насчет вашей точки зрения относительно файлов. <()Формат должен действовать как файл для всех намерений и целей. На самом деле, я не знаю ни одной команды, которая ожидает файл, который не будет удовлетворен <(). Те, которые не работают, ожидают имена файлов , а не файлов. Например, grep -fожидает файл и прекрасно работает с <().
Terdon
4
@terndon Наверняка <()выдает имя файла (конструкция распространяется /proc/self/fd/somethingна мою систему). При открытии это имя действует как конец чтения именованного канала ( S_IFIFO), а не как обычный файл ( S_IFREG), который поддерживает read()и другие, но не поддерживает seek().
Селада
7
Обратите внимание, что zshподдерживается третья форма замещения процесса, которая использует временные файлы специально для этой цели:gcc =(echo 'int main(){return 0;}')
Стефан Шазелас
может быть связано , но работает с, <(echo '...')но не с <(git show ...). Любая идея, почему это может быть?
Йорн Хис,
2
GCC не «выполняет произвольный доступ к своим входным файлам, чтобы определить, на каком языке они написаны». Он просто смотрит на расширение имени файла. Если имя файла не имеет расширения (или если оно имеет расширение, которое не распознано), GCC предполагает, что файл является объектным файлом или сценарием компоновщика, и передает его ld(который обнаруживает форматы объектов). -xэто не намек; это декларация. Если вы укажете -x f95, GCC передаст файл компилятору Fortran-95 независимо от его имени или содержимого. См. Gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Overages-Options.html
rici