Mengapa proses substitusi menghasilkan file bernama / dev / fd / 63 yang merupakan pipa?

40

Saya mencoba memahami pipa bernama dalam konteks contoh khusus ini.

Saya mengetik <(ls -l)terminal saya dan mendapatkan output sebagai bash: /dev/fd/63: Permission denied,.

Jika saya mengetik cat <(ls -l), saya bisa melihat isi direktori. Jika saya mengganti catdengan echo, saya pikir saya mendapatkan nama terminal (atau itu?).

echo <(ls -l)memberikan output sebagai /dev/fd/63.

Juga, contoh output ini tidak jelas bagi saya.

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

Namun, jika saya memberi, ls -l <()itu mencantumkan saya isi direktori.

Apa yang terjadi dalam kasus pipa bernama?

Ramesh
sumber

Jawaban:

37

Ketika Anda melakukannya <(some_command), shell Anda mengeksekusi perintah di dalam tanda kurung dan mengganti semuanya dengan deskriptor file, yang terhubung ke stdout perintah. Begitu /dev/fd/63juga pipa yang berisi output dari panggilan ls Anda.

Ketika Anda melakukannya, <(ls -l)Anda mendapatkan Permission deniedkesalahan, karena seluruh baris diganti dengan pipa, secara efektif mencoba memanggil /dev/fd/63sebagai perintah, yang tidak dapat dieksekusi.

Dalam contoh kedua Anda, cat <(ls -l)jadilah cat /dev/fd/63. Saat kucing membaca dari file yang diberikan sebagai parameter Anda mendapatkan konten. echodi sisi lain hanya menampilkan parameternya "apa adanya".

Kasus terakhir yang Anda miliki, <()hanya diganti dengan tidak ada, karena tidak ada perintah. Tapi ini tidak konsisten antara shell, di zsh Anda masih mendapatkan pipa (walaupun kosong).

Rangkuman : <(command)memungkinkan Anda menggunakan ouput dari sebuah perintah, di mana Anda biasanya membutuhkan file.

Sunting: seperti yang ditunjukkan Gilles , ini bukan pipa bernama, tetapi pipa anonim. Perbedaan utama adalah, bahwa itu hanya ada, selama proses berjalan, sementara pipa bernama (dibuat misalnya dengan mkfifo) akan tetap tanpa proses yang melekat padanya.

crater2150
sumber
5
mkfifohanya membuat pipa bernama, tanpa konten apa pun. Jadi, Anda perlu menulis sendiri (mis mkfifo mypipe; ls > mypipe.). Dan ya, tulisan ke pipa akan diblok sampai beberapa proses membaca dari pipa.
crater2150
6
Tidak ada pipa bernama di sini. /dev/fd/63adalah pipa anonim.
Gilles 'SO- stop being evil'
1
@ crater2150, @Gilles / dev / fd / 63 memang merupakan pipa bernama. Periksa ini dengan sesuatu seperti file <(ls). Shell memang membuat pipa anonim, tetapi deskriptor file mencerminkan sebagai pipa bernama di /dev/fd. Jika itu adalah pipa anonim, itu tidak akan memiliki nama dan tidak bisa dibuka oleh perintah yang /dev/fd/63dilewati.
rv
2
@ rv Ini masih pipa anonim. Fakta bahwa ada nama file yang merujuk ke pipa anonim ini tidak menjadikannya pipa bernama: pipa bernama berbeda, ada di suatu tempat di sistem file, memiliki izin dan kepemilikan, dll. Entri /dev/fddapat merujuk ke file apa pun deskriptor, bahkan pipa dan soket anonim, soket jaringan, segmen memori bersama, dll.
Gilles 'SO-stop being evil'
1
Tapi mengapa ini 63 ?
K3 --- rnc
-4

Anda salah memahami lsperintah dan pengalihan. lsdaftar file dan direktori yang diberikan pada baris perintah, saya tidak percaya menerima input dari stdin. Pengalihan > >>dan <merupakan cara untuk menggunakan file untuk memberi input dan mengumpulkan output.

rhubarbdog
sumber
1
Tidak ada pengalihan dari file di sini. <(…)adalah proses substitusi.
Gilles 'SO- stop being evil'
1
@IMSoP - seperti yang dikatakan Gilles - itu bukan pipa bernama - itu pipa anonim. Ini sangat mirip x|ydan hampir identik dengan [num]<<REDIRECTdi beberapa cangkang. Perbedaannya adalah substitusi literal dari tautan fd - /dev/fd/63dan lain-lain dan apa fungsinya - atau tidak dilakukan - dengan stdin. Lakukan echo | readlink /dev/fd/0dan lihat sendiri.
mikeserv
1
@IMSoP - itu adalah devtautan - file khusus. Anda dapat melakukan hal yang sama dengan deskriptor file apa saja pada sebagian besar sistem linux - bahkan tipikal |pipes, meskipun saya tidak menjamin perilaku di tempat lain. saya mendapatkan dari mana Anda berasal, tetapi pipa bernama adalah hal yang terpisah untuk dirinya sendiri - ini adalah referensi sistem file ke pipa di-kernel - referensi sistem file biasa , bukan file perangkat.
mikeserv
1
@ mikeserv Menariknya, manual Bash menyebutkan bahwa ia akan bekerja pada sistem tanpa /dev/fd/*membuat pipa bernama di tempat lain. Tapi saya berpendapat bahwa /dev/fd/*itu sendiri adalah mekanisme yang berbeda dari pipa bernama. Secara kebetulan, deskripsi Wikipedia dapat dilakukan dengan penjelasan tentang perbedaan ini.
IMSoP
1
@ mikeserv Menurut referensi lain yang saya temukan, lebih sederhana dari itu: jika /dev/fd/*tidak tersedia, bash akan membuat pipa bernama /tmp, dan menggunakannya sebagai pengganti proses. Sepertinya tidak aneh bagi saya, hanya membuat fungsionalitas tersedia di lingkungan sebanyak mungkin.
IMSoP