Apakah> & - lebih efisien daripada> / dev / null?

58

Kemarin saya membaca komentar SO ini yang mengatakan bahwa di shell (setidaknya bash) >&-"memiliki hasil yang sama dengan" >/dev/null.

Komentar itu sebenarnya merujuk pada panduan ABS sebagai sumber informasinya. Tetapi sumber itu mengatakan bahwa >&-sintaks "menutup deskriptor file".

Tidak jelas bagi saya apakah dua tindakan menutup deskriptor file dan mengarahkannya ke perangkat nol sama sekali setara. Jadi pertanyaan saya adalah: apakah mereka?

Di permukaan itu tampaknya menutup deskriptor seperti menutup pintu tetapi mengarahkannya ke perangkat nol membuka pintu ke limbo! Keduanya tampaknya tidak persis sama bagi saya karena jika saya melihat pintu yang tertutup, saya tidak akan mencoba untuk membuang apa pun darinya, tetapi jika saya melihat pintu yang terbuka saya akan menganggap saya bisa.

Dengan kata lain, saya selalu bertanya-tanya apakah >/dev/nullcara yang cat mybigfile >/dev/nullbenar-benar akan memproses setiap byte file dan menulisnya /dev/nullyang lupa. Di sisi lain, jika shell menemukan deskriptor file tertutup, saya cenderung berpikir (tapi tidak yakin) bahwa ia tidak akan menulis apa-apa, meskipun pertanyaannya tetap apakah catmasih akan membaca setiap byte.

Komentar ini mengatakan >&-dan >/dev/null" harus " sama, tetapi itu bukan jawaban yang meyakinkan bagi saya. Saya ingin memiliki jawaban yang lebih berwibawa dengan beberapa referensi ke standar atau sumber inti atau tidak ...

jamadagni
sumber
Jika saya ingin menjadi dermawan, saya akan mengatakan bahwa komentar itu tidak berarti bahwa mereka diimplementasikan dengan cara yang sama, hanya saja mereka berdua memiliki hasil akhir yang sama untuk mencegah Anda melihat hasil program.
Barmar

Jawaban:

71

Tidak, Anda tentu tidak ingin menutup deskriptor file 0, 1 dan 2.

Jika Anda melakukannya, pertama kali aplikasi membuka file, itu akan menjadi stdin / stdout / stderr ...

Misalnya, jika Anda melakukannya:

echo text | tee file >&-

Ketika tee(setidaknya beberapa implementasi, seperti busybox ') membuka file untuk ditulis, itu akan dibuka pada deskriptor file 1 (stdout). Jadi teeakan menulis textdua kali menjadi file:

$ echo text | strace tee file >&-
[...]
open("file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1
read(0, "text\n", 8193)                 = 5
write(1, "text\n", 5)                   = 5
write(1, "text\n", 5)                   = 5
read(0, "", 8193)                       = 0
exit_group(0)                           = ?

Itu telah diketahui menyebabkan kerentanan keamanan. Misalnya:

chsh 2>&-

Dan chsh(aplikasi setuid) mungkin berakhir dengan menulis pesan kesalahan di /etc/passwd.

Beberapa alat dan bahkan beberapa perpustakaan mencoba untuk menjaga itu. Sebagai contoh, GNU teeakan memindahkan deskriptor file ke yang di atas 2 jika file yang dibuka untuk penulisan diberikan 0, 1, 2 sedangkan busybox teetidak.

Sebagian besar alat, jika mereka tidak dapat menulis ke stdout (karena misalnya tidak terbuka), akan melaporkan pesan kesalahan pada stderr (dalam bahasa pengguna yang berarti pemrosesan ekstra untuk membuka dan mengurai file pelokalan ...), jadi itu akan secara signifikan kurang efisien, dan mungkin menyebabkan program gagal.

Bagaimanapun, itu tidak akan lebih efisien. Program masih akan melakukan write()panggilan sistem. Itu hanya bisa lebih efisien jika program menyerah menulis ke stdout / stderr setelah kegagalan write()sistem panggilan pertama, tetapi program umumnya tidak melakukan itu. Mereka umumnya keluar dengan kesalahan atau terus mencoba.

Stéphane Chazelas
sumber
4
Saya pikir jawaban ini akan lebih baik jika paragraf terakhir ada di atas (karena itulah yang paling langsung menjawab pertanyaan OP), dan kemudian melanjutkan untuk membahas mengapa itu adalah ide yang buruk bahkan jika itu sebagian besar bekerja. Tapi saya akan menerimanya, ada yang mendukung. ;)
CVn
@ StéphaneChazelas: Seperti yang dikatakan Michael, saya mengharapkan para terakhir di atas, tapi terima kasih untuk menjelaskannya sebenarnya mungkin hanya menciptakan masalah. Jadi saya kira pertanyaan tambahan akan, kapan penutupan FD benar-benar bermanfaat? Atau haruskah saya menanyakan hal itu sebagai pertanyaan terpisah?
jamadagni
@jamadagni, lihat unix.stackexchange.com/search?q=user%3A22565+%223%3E%26-%22 untuk beberapa contoh
Stéphane Chazelas
1
@jamadagni Jika tautan yang diberikan oleh Stéphane tidak menjawab pertanyaan, saya akan mengatakan bahwa itu terdengar seperti permulaan dari pertanyaan terpisah karena tidak terkait langsung dengan efisiensi relatif dari kedua metode.
CVn
1
Saya menghargai bahwa Stephane mulai dengan peringatan keamanan penting vert ini, karena akan kurang terlihat jika paragraf terakhir di atas. +1 dari saya.
Olivier Dulac
14

TKI saya selalu bertanya-tanya apakah >/dev/nullcara yang cat mybigfile >/dev/nullbenar-benar akan memproses setiap byte file dan menulisnya /dev/nullyang lupa itu.

Ini bukan jawaban lengkap untuk pertanyaan Anda, tetapi ya, di atas adalah cara kerjanya.

catmembaca file yang dinamai, atau input standar jika tidak ada file yang dinamai, dan output ke standarnya mengeluarkan konten tersebut sampai bertemu EOF pada (termasuk input standar) file terakhir yang dinamai. Itulah yang pekerjaan.

Dengan menambahkan >/dev/nullAnda mengarahkan output standar ke / dev / null. Itu adalah file khusus (simpul perangkat) yang membuang apa pun yang tertulis di dalamnya (dan segera mengembalikan EOF saat dibaca). Perhatikan bahwa pengalihan I / O adalah fitur yang disediakan oleh shell, bukan oleh masing-masing aplikasi individual, dan bahwa tidak ada yang ajaib tentang nama / dev / null, hanya apa yang terjadi di sebagian besar sistem mirip Unix .

Penting juga untuk dicatat bahwa mekanisme spesifik node perangkat bervariasi dari satu sistem operasi ke sistem operasi, tetapi cat (yang, dalam sistem GNU, berarti coreutils) adalah lintas-platform (kode sumber yang sama perlu dijalankan setidaknya di Linux dan Hurd) dan karenanya tidak dapat membawa dependensi ke kernel sistem operasi tertentu. Selain itu, ia masih berfungsi jika Anda membuat alias / dev / null (di Linux, ini berarti simpul perangkat dengan nomor perangkat utama / minor yang sama) dengan nama lain. Dan selalu ada kasus menulis di tempat lain yang berperilaku sama secara efektif (katakanlah, / dev / nol).

Ini mengikuti yang cattidak mengetahui properti khusus dari / dev / null, dan memang mungkin tidak menyadari pengalihan di tempat pertama, tetapi masih perlu melakukan pekerjaan yang persis sama: membaca file yang dinamai, dan menampilkan konten dari file tersebut untuk output standarnya. Bahwa keluaran standar dari catkekosongan bukanlah sesuatu catyang dikhawatirkan.

sebuah CVn
sumber
2
Untuk memperluas jawaban Anda: Ya, cat mybigfile > /dev/nullakan menyebabkan catmembaca setiap byte bigfileke dalam memori. Dan, untuk setiap nbyte, itu akan memanggil write(1, buffer, n). Tanpa diketahui catprogram, writeakan melakukan apa-apa (kecuali mungkin untuk beberapa pembukuan sepele). Menulis ke /dev/nulltidak memerlukan pemrosesan setiap byte.
G-Man Mengatakan 'Reinstate Monica'
2
Saya ingat saya terpesona ketika saya membaca sumber kernel Linux dari perangkat / dev / null. Saya berharap ada beberapa sistem yang rumit dari buffer gratis (), dll, tapi, tidak, itu pada dasarnya hanya return ().
Brian Minton
4
@ G-Man: Saya tidak tahu Anda bisa menjamin itu benar dalam semua kasus. Saya tidak dapat menemukan bukti sekarang, tetapi saya ingat beberapa implementasi salah satu catatau cpyang akan bekerja dengan mmapmemasukkan potongan besar file sumber ke dalam memori, kemudian memanggil write()wilayah yang dipetakan. Jika Anda menulis /dev/nullsurat kepada , write()panggilan akan kembali sekaligus tanpa kesalahan pada halaman file sumber, sehingga tidak akan pernah benar-benar dibaca dari disk.
Nate Eldredge
2
Juga, sesuatu seperti GNU catberjalan pada banyak platform, tetapi pandangan sekilas pada kode sumber akan menunjukkan banyak #ifdefs: itu bukan kode yang sama yang berjalan pada semua platform, dan ada banyak bagian yang bergantung pada sistem.
Nate Eldredge
@NateEldredge: Poin yang menarik, tapi saya baru saja membangun jawaban Michael, jadi Anda tidak terlalu kontradiktif dengan saya karena Anda bertentangan dengan Michael.
G-Man Mengatakan 'Reinstate Monica'