Чому заміна процесу 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)


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. Усі оболонки, які підтримують процес заміщення, поводяться однаково.


+1 для вирішення проблеми gcc, але я не впевнений у вашій точці щодо файлів. <()Формат повинен діяти як файл для всіх намірів і цілей. Насправді я не знаю жодної команди, яка очікує на файл, який не буде задоволений <(). Ті, які не працюють, - це ті, які очікують імен файлів , а не файлів. Наприклад, grep -fочікує, що файл і добре працює з <().
тердон

4
@terndon Напевно <()створює ім'я файлу (конструкція розширюється /proc/self/fd/somethingна мою систему). Це ім'я, відкриваючись, діє як кінець зчитування іменованого каналу ( S_IFIFO), а не звичайний файл ( S_IFREG) у тому, що підтримує read()та інші, але не seek().
Селада

7
Зауважте, що zshпідтримується 3-та форма заміни процесу, яка використовує тимчасові файли спеціально для цієї мети:gcc =(echo 'int main(){return 0;}')
Stéphane Chazelas

можливо, пов’язаний , але працює з, <(echo '...')але не з <(git show ...). будь-яка ідея, чому це могло бути?
Йорн Хес

2
GCC не "виконує випадковий доступ до своїх вхідних файлів, щоб виявити, на якій мові вони написані". Він просто розглядає розширення назви файлу. Якщо ім'я файлу не має розширення (або якщо воно має таке, яке не розпізнається), GCC припускає, що цей файл є об’єктним файлом або скриптом посилання, і передає його ld(який виявляє формати об'єктів). -xне є натяком; це декларація. Якщо вказати -x f95, GCC передасть файл компілятору Fortran-95 незалежно від його імені чи вмісту. Дивіться gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Overall-Options.html
rici
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.