Mengapa substitusi proses BASH tidak berfungsi dengan beberapa perintah?

29

Kadang-kadang proses substitusi tidak akan berfungsi seperti yang diharapkan. Berikut ini sebuah contoh:

Memasukkan:

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

Keluaran:

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

Memasukkan:

Tetapi berfungsi seperti yang diharapkan ketika digunakan dengan perintah yang berbeda:

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

Keluaran:

int main(){return 0;}

Saya telah memperhatikan kegagalan yang sama dengan perintah lain (yaitu perintah yang mengharapkan file dari proses substitusi tidak dapat digunakan /dev/fd/63atau serupa). Kegagalan dengan gccini adalah yang terbaru. Apakah ada beberapa aturan umum yang harus saya waspadai untuk menentukan kapan proses penggantian akan gagal dengan cara ini dan tidak boleh digunakan?

Saya menggunakan versi BASH ini di Ubuntu 12.04 (Saya juga melihat ini di arch dan debian):
GNU bash, versi 4.3.11 (1) -release (i686-pc-linux-gnu)

Lotney
sumber
1
illegal seeksepertinya jawabannya - |pipeyang bashmenunjukkan program yang dijalankan bukan file yang bisa dicari. mungkin jika Anda tidak dapat berhasil echo data | command /dev/fd/0di suatu program maka Anda akan memiliki keberuntungan yang sama dengan / <(cmd). Itu tidak menyediakan file pada disk - itu hanya menggantikan argumen yang menunjuk ke descriptor file pipa.
mikeserv
2
Dalam kasus khusus ini, meskipun gcc dapat menerima input standar, itu (secara default) menggunakan ekstensi nama file untuk menentukan bahasa. Jadi coba gcc -xc <(echo 'int main(){return 0;}')(yang mengatur bahasa Csecara eksplisit).
steeldriver
Saya diarahkan ke sini untuk menjawab pertanyaan saya sendiri, yang sepertinya merupakan contoh lain dari ini. superuser.com/questions/1243405 . Terima kasih telah mengutarakan pertanyaan dengan lebih baik daripada yang saya bisa.
Jonathan Hartley

Jawaban:

33

Proses subtitusi menghasilkan file khusus (seperti /dev/fd/63dalam contoh Anda) yang berperilaku seperti ujung baca dari pipa bernama. File ini dapat dibuka dan dibaca, tetapi tidak ditulis, tidak dicari.

Perintah yang memperlakukan argumen mereka sebagai stream murni berfungsi sementara perintah yang berharap untuk mencari dalam file yang diberikan (atau menulis kepada mereka) tidak akan berfungsi. Jenis perintah yang akan bekerja adalah apa yang biasanya dianggap sebagai filter: cat, grep, sed, gzip, awk, dll ... Contoh perintah yang tidak akan bekerja adalah editor seperti viatau operasi file seperti mv.

gccingin dapat melakukan akses acak pada file inputnya untuk mendeteksi bahasa apa yang mereka tulis. Jika Anda memberikan gccpetunjuk tentang bahasa file input, senang untuk melakukan streaming file:

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

Bentuk yang lebih sederhana dan tanpa proses substitusi juga berfungsi:

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

Perhatikan bahwa ini tidak spesifik untuk bash. Semua shell yang mendukung substitusi proses berperilaku dengan cara yang sama.

Celada
sumber
+1 untuk solusi gcc tapi saya tidak yakin tentang poin Anda tentang file. The <()Format harus bertindak seperti sebuah file untuk semua maksud dan tujuan. Bahkan, saya tidak tahu ada perintah yang mengharapkan file yang tidak akan senang <(). Yang tidak berfungsi adalah mereka yang mengharapkan nama file , bukan file. Misalnya, grep -fmengharapkan file dan berfungsi dengan baik <().
terdon
4
@terndon For sure <()menghasilkan nama file (konstruk memperluas ke /proc/self/fd/somethingsistem saya). Nama ini, ketika dibuka, bertindak seperti ujung baca dari pipa bernama ( S_IFIFO) daripada file biasa ( S_IFREG) di yang mendukung read()dan lain-lain tetapi tidak seek().
Celada
7
Catatan yang zshmendukung bentuk substitusi proses ke-3 yang menggunakan file sementara terutama untuk tujuan itu:gcc =(echo 'int main(){return 0;}')
Stéphane Chazelas
mungkin terkait , tetapi bekerja dengan <(echo '...')tetapi tidak dengan <(git show ...). tahu mengapa itu bisa terjadi?
Jörn Hees
2
GCC tidak "melakukan akses acak pada file inputnya untuk mendeteksi bahasa apa yang mereka tulis." Itu hanya melihat ekstensi nama file. Jika nama file tidak memiliki ekstensi (atau jika memiliki yang tidak dikenali), GCC menganggap file tersebut adalah file objek atau skrip linker dan meneruskannya ke ld(yang mendeteksi format objek). -xbukan sebuah petunjuk; itu adalah deklarasi. Jika Anda menentukan -x f95, GCC akan meneruskan file ke kompiler Fortran-95 terlepas dari nama atau isinya. Lihat gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Overall-Options.html
rici