Saya mencoba memahami konsep file khusus di Linux. Namun, memiliki file khusus /dev
tampaknya konyol ketika fungsinya dapat diimplementasikan oleh beberapa baris dalam C sepengetahuan saya.
Selain itu, Anda bisa menggunakannya dengan cara yang hampir sama, yaitu menyalurkan ke null
alih alih mengarahkan /dev/null
. Apakah ada alasan khusus untuk menjadikannya sebagai file? Tidak menjadikannya file yang menyebabkan banyak masalah lain seperti terlalu banyak program yang mengakses file yang sama?
files
devices
executable
null
Ankur S
sumber
sumber
cat foo | bar
jauh lebih buruk (pada skala) daripadabar <foo
.cat
adalah program sepele, tetapi bahkan sebuah program sepele menciptakan biaya (beberapa di antaranya khusus untuk semantik FIFO - karena program tidak dapatseek()
di dalam FIFO, misalnya, sebuah program yang dapat diimplementasikan secara efisien dengan pencarian dapat berakhir dengan melakukan operasi yang jauh lebih mahal. ketika diberi saluran pipa; dengan perangkat karakter seperti/dev/null
itu dapat memalsukan operasi tersebut, atau dengan file nyata dapat menerapkannya, tetapi FIFO tidak mengizinkan segala jenis penanganan sadar kontekstual).grep blablubb file.txt 2>/dev/null && dosomething
tidak dapat bekerja dengan null sebagai program atau fungsi.read
fungsi untuk/dev/null
terdiri dari "return 0" (artinya tidak melakukan apa-apa dan, saya kira, menghasilkan EOF): (Dari static github.com/torvalds/linux/blob/master/ driver / char / mem.c )ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) { return 0; }
(Oh, saya baru saja melihat bahwa @JdeBP sudah membuat poin itu. Bagaimanapun, berikut ini ilustrasinya :-).Jawaban:
Selain manfaat kinerja menggunakan perangkat khusus karakter, manfaat utama adalah modularitas . / dev / null dapat digunakan di hampir semua konteks di mana file diharapkan, bukan hanya di jaringan pipa shell. Pertimbangkan program yang menerima file sebagai parameter baris perintah.
Ini semua adalah kasus di mana menggunakan program sebagai sumber atau bak cuci akan sangat rumit. Bahkan dalam kasus shell pipeline, stdout dan stderr dapat diarahkan ke file secara mandiri, sesuatu yang sulit dilakukan dengan executable seperti sink:
sumber
/dev/null
perintah shell saja. Anda dapat menggunakannya dalam parameter lain yang disediakan untuk perangkat lunak --- misalnya dalam file konfigurasi. --- Fort software ini sangat nyaman. Tidak perlu membuat perbedaan antara/dev/null
dan file biasa.pipe
,fork
danexecve
seperti pipa proses lainnya, hanya dengan perubahan padadup2
panggilan yang mengatur koneksi, kan? Memang benar sebagian besar shell tidak menawarkan cara tercantik untuk melakukannya, tetapi mungkin jika kita tidak memiliki begitu banyak pola perangkat-sebagai-file dan sebagian besar hal-hal di/dev
dan/proc
diperlakukan sebagai executable, shell akan dirancang dengan cara untuk melakukannya semudah kita mengarahkan sekarang.wait4
! Anda benar, tentu saja mungkin untuk mem-pipe stdout dan stderr ke program yang berbeda menggunakan apis POSIX, dan dimungkinkan untuk menciptakan sintaksis shell yang pintar untuk mengarahkan stdout dan stderr ke perintah yang berbeda. Namun, saya tidak mengetahui adanya shell seperti itu sekarang, dan poin yang lebih besar adalah bahwa / dev / null cocok dengan tooling yang ada (yang sebagian besar bekerja dengan file), dan / bin / null tidak akan. Kita juga bisa membayangkan beberapa IO API yang membuatnya mudah bagi gcc untuk (secara aman!) Meng-output ke suatu program seperti file, tetapi itu bukan situasi kita sekarang.grep localhost /dev/ /etc/hosts 2> >(sed 's/^/STDERR:/' > errfile ) > >(sed 's/^/STDOUT:/' > outfile)
, menghasilkan diproses secara terpisaherrfile
danoutfile
Dalam keadilan, ini bukan file biasa per se; itu adalah perangkat khusus karakter :
Ini berfungsi sebagai perangkat dan bukan sebagai file atau program berarti itu adalah operasi yang lebih sederhana untuk mengarahkan input atau output dari itu, karena dapat dilampirkan ke deskriptor file apa pun, termasuk input / output / kesalahan standar.
sumber
cat file | null
akan memiliki banyak overhead, pertama dalam menyiapkan pipa, memunculkan proses, mengeksekusi "null" dalam proses baru, dll. Juga,null
itu sendiri akan menggunakan sedikit CPU dalam loop membaca byte ke buffer yang kemudian baru saja dibuang ... Implementasi/dev/null
di kernel hanya lebih efisien dengan cara itu. Juga, bagaimana jika Anda ingin memberikan/dev/null
argumen, alih-alih pengalihan? (Anda bisa menggunakannya<(...)
di bash, tapi itu cara yang lebih berat!)null
Alih-alih menggunakan pengalihan/dev/null
, apakah akan ada cara sederhana dan jelas untuk memberi tahu shell untuk menjalankan program sambil mengirimkan hanya stderr ke nol?/dev/zero
sebagai gantinya.dd of=-
menulis ke file bernama-
, hanya menghilangkanof=
untuk menulis ke stdout karena di situlahdd
menulis secara default. Perpipaan kefalse
tidak akan berfungsi karenafalse
tidak membaca stdin, jadidd
akan dibunuh dengan SIGPIPE. Untuk perintah yang membuang input Anda dapat menggunakan ...cat > /dev/null
. Juga perbandingan yang mungkin tidak relevan sebagai leher botol mungkin akan menjadi generasi nomor acak di sini.dd
dll. Bahkan tidak repot-repot melakukan syscall tulis ketika mereka mendeteksi tujuannya adalah / dev / null.Saya curiga mengapa ada banyak hubungannya dengan visi / desain yang berbentuk Unix (dan akibatnya Linux), dan keuntungan yang berasal dari itu.
Tidak diragukan lagi ada manfaat kinerja yang tidak dapat diabaikan untuk tidak memutar proses tambahan, tapi saya pikir ada lebih dari itu: Early Unix memiliki metafora "semuanya adalah file", yang memiliki keuntungan yang tidak jelas namun elegan jika Anda melihat itu dari perspektif sistem, bukan dari perspektif skrip shell.
Katakanlah Anda memiliki
null
program command-line Anda, dan/dev/null
simpul perangkat. Dari perspektif shell-scripting,foo | null
program ini benar-benar berguna dan nyaman , danfoo >/dev/null
membutuhkan sedikit waktu lebih lama untuk mengetik dan bisa terasa aneh.Tapi inilah dua latihan:
Mari kita melaksanakan program
null
menggunakan alat Unix yang ada dan/dev/null
- mudah:cat >/dev/null
. Selesai.Anda dapat menerapkan
/dev/null
dalam halnull
?Anda memang benar bahwa kode C untuk hanya membuang input itu sepele, jadi mungkin belum jelas mengapa ada file virtual yang tersedia untuk tugas tersebut.
Pertimbangkan: hampir setiap bahasa pemrograman sudah perlu bekerja dengan file, deskriptor file, dan path file, karena mereka adalah bagian dari paradigma "semuanya adalah file" dari awal.
Jika semua yang Anda miliki adalah program yang menulis ke stdout, well, program tidak peduli jika Anda mengarahkan mereka ke file virtual yang menelan semua penulisan, atau pipa ke program yang menelan semua penulisan.
Sekarang jika Anda memiliki program yang mengambil jalur file untuk membaca atau menulis data (yang dilakukan sebagian besar program) - dan Anda ingin menambahkan fungsionalitas "input kosong" atau "buang hasil ini" ke program-program tersebut - yah, dengan
/dev/null
yang gratis.Perhatikan bahwa keanggunannya adalah mengurangi kompleksitas kode dari semua program yang terlibat - untuk setiap usecase umum-tetapi-khusus yang dapat disediakan oleh sistem Anda sebagai "file" dengan "nama file" yang sebenarnya, kode Anda dapat menghindari penambahan perintah kustom Opsi-line dan jalur kode khusus untuk ditangani.
Rekayasa perangkat lunak yang baik sering tergantung pada menemukan metafora yang baik atau "alami" untuk mengabstraksi beberapa elemen masalah dengan cara yang menjadi lebih mudah untuk dipikirkan tetapi tetap fleksibel , sehingga Anda dapat memecahkan berbagai masalah tingkat tinggi yang pada dasarnya sama tanpa harus menghabiskan waktu dan energi mental untuk mengimplementasikan kembali solusi untuk masalah tingkat rendah yang sama secara konstan.
"Semuanya adalah file" tampaknya menjadi salah satu metafora untuk mengakses sumber daya: Anda memanggil
open
jalur yang diberikan dalam namespace heirarkis, mendapatkan referensi (deskriptor file) ke objek, dan Anda dapatread
danwrite
, dll pada deskriptor file. Stdin / stdout / stderr Anda juga deskriptor file yang baru saja dibuka sebelumnya untuk Anda. Pipa Anda hanyalah file dan deskriptor file, dan pengalihan file memungkinkan Anda merekatkan semua bagian ini.Unix berhasil seperti halnya sebagian karena seberapa baik abstraksi ini bekerja bersama, dan
/dev/null
paling baik dipahami sebagai bagian dari keseluruhan itu.PS Ada baiknya melihat versi Unix dari "semuanya adalah file" dan hal-hal seperti
/dev/null
sebagai langkah pertama menuju generalisasi metafora yang lebih fleksibel dan kuat yang telah diterapkan di banyak sistem yang mengikuti.Sebagai contoh, di Unix objek seperti file khusus seperti
/dev/null
harus diimplementasikan dalam kernel itu sendiri, tetapi ternyata cukup berguna untuk mengekspos fungsionalitas dalam bentuk file / folder yang sejak itu banyak sistem telah dibuat yang menyediakan jalan bagi program untuk melakukannya.Salah satu yang pertama adalah sistem operasi Plan 9, yang dibuat oleh beberapa orang yang sama yang membuat Unix. Kemudian, GNU Hurd melakukan sesuatu yang mirip dengan "penerjemahnya". Sementara itu, Linux akhirnya mendapatkan FUSE (yang telah menyebar ke sistem arus utama lainnya sekarang juga).
sumber
NUL
muncul di setiap direktori, yaitu yang harus Anda ketikkan adalah> NUL
.Saya pikir
/dev/null
adalah perangkat karakter (yang berperilaku seperti file biasa), bukan program untuk alasan kinerja .Jika itu akan menjadi sebuah program, itu akan memerlukan memuat, memulai, menjadwalkan, menjalankan, dan setelah itu menghentikan dan membongkar program. Program C sederhana yang Anda gambarkan tentu saja tidak akan menghabiskan banyak sumber daya, tetapi saya pikir itu membuat perbedaan yang signifikan ketika mempertimbangkan sejumlah besar (katakanlah jutaan) tindakan pengalihan / perpipaan karena operasi manajemen proses mahal dalam skala besar seperti mereka melibatkan sakelar konteks.
Asumsi lain: Memipipkan ke dalam suatu program membutuhkan memori yang akan dialokasikan oleh program penerima (bahkan jika itu dibuang langsung sesudahnya). Jadi, jika Anda menyambungkan ke alat Anda memiliki konsumsi memori ganda, sekali pada program pengiriman dan sekali lagi pada program penerima.
sumber
read
datanya). Ini tidak dapat diabaikan pada single-core PDP-11 di mana Unix dirancang! Bandwidth memori / menyalin jauh lebih murah hari ini daripada saat itu. Sebuahwrite
sistem panggilan ke FD terbuka pada/dev/null
dapat kembali segera tanpa membaca data dari buffer.null
program akan menyedot, tetapi kebanyakan CPU multi-core tidak berjalan dengan semua core sibuk sepanjang waktu, jadi Waktu CPU untuk menjalankannull
program ini sebagian besar gratis. Pada sistem dengan semua inti yang dipatok, perpipaan yang tidak berguna adalah masalah yang lebih besar. Tapi tidak, buffer "hot" dapat ditulis ulang berkali-kali tanpa mendapatkan RAM, jadi kita sebagian besar hanya bersaing untuk bandwidth L3, bukan cache. Tidak hebat, terutama pada sistem SMT (hyperthreading) di mana inti logis lain (s) pada fisik yang sama bersaing ...vpaddd zmm
: 16 elemen 32-bit per instruksi.Selain "semuanya adalah file" dan karenanya mudah digunakan di mana-mana berdasarkan sebagian besar jawaban lain, ada juga masalah kinerja seperti yang disebutkan oleh @ user5626466.
Untuk ditampilkan dalam praktik, kami akan membuat program sederhana bernama
nullread.c
:dan kompilasi dengan
gcc -O2 -Wall -W nullread.c -o nullread
(Catatan: kita tidak dapat menggunakan lseek (2) pada pipa, jadi satu-satunya cara untuk mengeringkan pipa adalah dengan membacanya sampai kosong).
sedangkan dengan
/dev/null
redirection file standar, kami mendapatkan kecepatan yang jauh lebih baik (karena fakta-fakta yang disebutkan: kurang konteks switching, kernel hanya mengabaikan data daripada menyalinnya dll):(ini seharusnya menjadi komentar di sana, tetapi terlalu besar untuk itu dan benar-benar tidak dapat dibaca)
sumber
dd
buffer Anda + menerima buffer tidak cocok; Anda mungkin berurusan dengan bandwidth memori, bukan bandwidth cache level terakhir. Anda mungkin mendapatkan bandwidth yang lebih baik dengan buffer 512k atau bahkan buffer 64k. (Menurutstrace
pada desktop saya,write
danread
mengembalikan 1048576, jadi saya pikir itu berarti kami hanya membayar pengguna <-> biaya kernel dari TLB invalidation + flush prediksi cabang sekali per MiB, bukan per 64k, @sourcejedi. Spectre mitigasi yang memiliki biaya paling besar, saya pikir)syscall
yang segera kembaliENOSYS
adalah ~ 1800 siklus Skylake dengan mitigasi Specter diaktifkan, sebagian besar adalahwrmsr
yang membatalkan BPU, menurut pengujian @ BeeOnRope . Dengan mitigasi dinonaktifkan, waktu pulang pergi pengguna-> kernel-> ~ 160 siklus. Tetapi jika Anda adalah menyentuh banyak memori, mitigasi Meltdown signifikan, juga. Hugepages harus membantu (lebih sedikit entri TLB perlu dimuat ulang).Pertanyaan Anda diajukan seolah-olah sesuatu akan diperoleh mungkin dalam kesederhanaan dengan menggunakan program nol sebagai pengganti file. Mungkin kita bisa menyingkirkan gagasan "file ajaib" dan sebagai gantinya hanya "pipa biasa".
Tapi pertimbangkan, pipa juga file . Mereka biasanya tidak dinamai, dan hanya dapat dimanipulasi melalui deskriptor file mereka.
Pertimbangkan contoh yang agak dibuat-buat ini:
Dengan menggunakan proses substitusi Bash kita dapat mencapai hal yang sama melalui cara yang lebih bundaran:
Ganti
grep
untukecho
dan kita bisa lihat di bawah selimut:The
<(...)
konstruk hanya diganti dengan nama file, dan grep berpikir itu adalah membuka file lama, itu hanya terjadi untuk diberi nama/dev/fd/63
. Di sini,/dev/fd
adalah direktori ajaib yang membuat pipa bernama untuk setiap deskriptor file yang dimiliki oleh file yang mengaksesnya.Kita bisa membuatnya kurang ajaib dengan
mkfifo
membuat pipa bernama yang munculls
dan semuanya, seperti file biasa:Di tempat lain:
dan lihat, grep akan menampilkan
foo
.Saya pikir begitu Anda menyadari pipa dan file biasa dan file khusus seperti / dev / null semua hanya file, jelas menerapkan program nol lebih kompleks. Kernel harus menangani penulisan ke file dengan cara apa pun, tetapi dalam kasus / dev / null ia hanya dapat meletakkan tulisan di lantai, sedangkan dengan pipa ia harus benar-benar mentransfer byte ke program lain, yang kemudian harus sebenarnya membacanya.
sumber
/dev/fd/63
?Saya berpendapat bahwa ada masalah keamanan di luar paradigma dan kinerja historis. Membatasi jumlah program dengan kredensial eksekusi istimewa, tidak peduli sesederhana apa pun, merupakan prinsip mendasar keamanan sistem. Pengganti
/dev/null
tentu diperlukan untuk memiliki hak istimewa seperti itu karena digunakan oleh layanan sistem. Kerangka kerja keamanan modern melakukan pekerjaan yang sangat baik untuk mencegah eksploitasi, tetapi tidak mudah. Perangkat berbasis kernel yang diakses sebagai file jauh lebih sulit untuk dieksploitasi.sumber
/dev/null
atau program input-discarding yang diusulkan, vektor serangan akan sama: dapatkan skrip atau program yang berjalan sebagai root untuk melakukan sesuatu yang aneh (seperti mencobalseek
masuk/dev/null
atau membuka beberapa kali dari proses yang sama, atau IDK apa. Atau memohon/bin/null
dengan lingkungan yang aneh, atau apa pun).Seperti orang lain sudah tunjukkan,
/dev/null
adalah program yang dibuat dari beberapa baris kode. Hanya saja baris kode ini adalah bagian dari kernel.Untuk membuatnya lebih jelas, inilah implementasi Linux: perangkat karakter memanggil fungsi saat membaca atau menulis. Menulis ke
/dev/null
panggilan write_null , saat membaca panggilan read_null , terdaftar di sini .Secara harfiah beberapa baris kode: fungsi-fungsi ini tidak melakukan apa pun. Anda akan membutuhkan lebih banyak baris kode daripada jari di tangan Anda hanya jika Anda menghitung fungsi selain membaca dan menulis.
sumber
Saya harap Anda juga mengetahui / dev / chargen / dev / zero dan lainnya seperti mereka termasuk / dev / null.
LINUX / UNIX memiliki beberapa di antaranya - yang tersedia sehingga orang dapat memanfaatkan dengan baik BAGIAN KODE TERTULIS.
Chargen dirancang untuk menghasilkan pola karakter yang spesifik dan berulang - cukup cepat dan akan mendorong batas perangkat serial dan itu akan membantu men-debug protokol serial yang ditulis dan gagal dalam beberapa tes atau lainnya.
Nol dirancang untuk mengisi file yang ada atau menghasilkan banyak nol
/ dev / null hanyalah alat lain dengan ide yang sama.
Semua alat ini di toolkit Anda berarti bahwa Anda memiliki kesempatan untuk membuat program yang ada melakukan sesuatu yang unik tanpa memperhatikan mereka (kebutuhan spesifik Anda) sebagai penggantian perangkat atau file
Mari kita siapkan kontes untuk melihat siapa yang dapat menghasilkan hasil paling menarik mengingat hanya beberapa perangkat karakter dalam versi LINUX Anda.
sumber