Mengapa / dev / null sebuah file? Mengapa fungsinya tidak diimplementasikan sebagai program sederhana?

114

Saya mencoba memahami konsep file khusus di Linux. Namun, memiliki file khusus /devtampaknya 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 nullalih 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?

Ankur S
sumber
20
Kebetulan, banyak overhead ini juga mengapa cat foo | barjauh lebih buruk (pada skala) daripada bar <foo. catadalah program sepele, tetapi bahkan sebuah program sepele menciptakan biaya (beberapa di antaranya khusus untuk semantik FIFO - karena program tidak dapat seek()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/nullitu dapat memalsukan operasi tersebut, atau dengan file nyata dapat menerapkannya, tetapi FIFO tidak mengizinkan segala jenis penanganan sadar kontekstual).
Charles Duffy
13
grep blablubb file.txt 2>/dev/null && dosomethingtidak dapat bekerja dengan null sebagai program atau fungsi.
rexkogitans
16
Anda mungkin menemukan itu mencerahkan (atau setidaknya memperluas pikiran) untuk membaca tentang sistem operasi Plan 9 untuk melihat di mana visi "semuanya adalah file" - menjadi sedikit lebih mudah untuk melihat kekuatan memiliki sumber daya yang tersedia sebagai file jalan begitu Anda melihat sistem sepenuhnya merangkul konsep (daripada sebagian besar / sebagian, seperti Linux / Unix modern lakukan).
mtraceur
25
Selain tidak ada yang menunjukkan bahwa driver perangkat yang berjalan di ruang kernel adalah program dengan "beberapa baris C" , tidak ada jawaban sejauh ini yang benar-benar menjawab anggapan "terlalu banyak program mengakses file yang sama" dalam pertanyaan.
JdeBP
12
Re "fungsinya dapat diimplementasikan oleh beberapa baris di C": Anda tidak akan mempercayainya, tetapi ini diterapkan oleh beberapa baris di C! Misalnya, badan readfungsi untuk /dev/nullterdiri 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 :-).
Peter A. Schneider

Jawaban:

153

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.

# We don't care about log output.
$ frobify --log-file=/dev/null

# We are not interested in the compiled binary, just seeing if there are errors.
$ gcc foo.c -o /dev/null  || echo "foo.c does not compile!".

# Easy way to force an empty list of exceptions.
$ start_firewall --exception_list=/dev/null

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:

# Suppress errors, but print output.
$ grep foo * 2>/dev/null
ioctl
sumber
14
Anda juga tidak menggunakan /dev/nullperintah 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/nulldan file biasa.
pabouk
Saya tidak yakin saya mengerti bagian tentang pengalihan terpisah untuk menenggelamkan executables menjadi sulit. Dalam C, Anda hanya melakukan pipe, forkdan execveseperti pipa proses lainnya, hanya dengan perubahan pada dup2panggilan 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 /devdan /procdiperlakukan sebagai executable, shell akan dirancang dengan cara untuk melakukannya semudah kita mengarahkan sekarang.
aschepler
6
@aschepler Itu tidak mengarahkan redirect ke tenggelam executable sulit. Menulis aplikasi yang dapat menulis ke / membaca dari kedua file dan null sink akan lebih rumit jika null sink bukan file. Kecuali Anda berbicara tentang dunia di mana alih-alih semuanya menjadi file, semuanya dapat dieksekusi? Itu akan menjadi model yang sangat berbeda dari yang Anda miliki di * nix OS.
Cubic
1
@aschepler Anda lupa 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.
ioctl
2
@ ioctl tentang kerang; zsh dan bash setidaknya akan memungkinkan Anda untuk melakukan hal-hal seperti grep localhost /dev/ /etc/hosts 2> >(sed 's/^/STDERR:/' > errfile ) > >(sed 's/^/STDOUT:/' > outfile), menghasilkan diproses secara terpisah errfiledanoutfile
Matija Nalis
62

Dalam keadilan, ini bukan file biasa per se; itu adalah perangkat khusus karakter :

$ file /dev/null
/dev/null: character special (3/2)

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.

DopeGhoti
sumber
24
cat file | nullakan memiliki banyak overhead, pertama dalam menyiapkan pipa, memunculkan proses, mengeksekusi "null" dalam proses baru, dll. Juga, nullitu sendiri akan menggunakan sedikit CPU dalam loop membaca byte ke buffer yang kemudian baru saja dibuang ... Implementasi /dev/nulldi kernel hanya lebih efisien dengan cara itu. Juga, bagaimana jika Anda ingin memberikan /dev/nullargumen, alih-alih pengalihan? (Anda bisa menggunakannya <(...)di bash, tapi itu cara yang lebih berat!)
filbranden
4
Jika Anda harus mem-pipe ke sebuah program bernama nullAlih-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?
Mark Plotnick
5
Ini adalah pengaturan yang sangat mahal untuk demonstrasi overhead. Saya sarankan menggunakan /dev/zerosebagai gantinya.
chrylis -on strike-
20
Contoh-contoh itu salah. dd of=-menulis ke file bernama -, hanya menghilangkan of=untuk menulis ke stdout karena di situlah ddmenulis secara default. Perpipaan ke falsetidak akan berfungsi karena falsetidak membaca stdin, jadi ddakan 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.
Stéphane Chazelas
8
Versi AST dddll. Bahkan tidak repot-repot melakukan syscall tulis ketika mereka mendeteksi tujuannya adalah / dev / null.
Mark Plotnick
54

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 nullprogram command-line Anda, dan /dev/nullsimpul perangkat. Dari perspektif shell-scripting, foo | nullprogram ini benar-benar berguna dan nyaman , dan foo >/dev/nullmembutuhkan sedikit waktu lebih lama untuk mengetik dan bisa terasa aneh.

Tapi inilah dua latihan:

  1. Mari kita melaksanakan program nullmenggunakan alat Unix yang ada dan /dev/null- mudah: cat >/dev/null. Selesai.

  2. Anda dapat menerapkan /dev/nulldalam hal null?

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/nullyang 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 openjalur yang diberikan dalam namespace heirarkis, mendapatkan referensi (deskriptor file) ke objek, dan Anda dapat readdan write, 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/nullpaling baik dipahami sebagai bagian dari keseluruhan itu.


PS Ada baiknya melihat versi Unix dari "semuanya adalah file" dan hal-hal seperti /dev/nullsebagai 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/nullharus 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).

mtraceur
sumber
8
@PeterCordes titik jawabannya dimulai dari posisi tidak memahami desain. Jika semua orang sudah memahami desain, pertanyaan ini tidak akan ada.
OrangeDog
1
@ trtrur: Mount file gambar tanpa izin root? menunjukkan beberapa bukti bahwa FUSE mungkin tidak memerlukan root, tapi saya tidak yakin.
Peter Cordes
1
@PeterCordes RE: "sepertinya aneh": Ini bukan permintaan maaf untuk desain, hanya pengakuan tentang bagaimana hal itu dapat terlihat jika Anda tidak memikirkan implementasi sistem di bawahnya, dan belum memiliki momen eureka tentang sistem -keuntungan desain yang luas. Saya mencoba memperjelasnya dengan membuka kalimat itu dengan "dari perspektif shell scripting", dan menyinggung perbedaan antara itu vs perspektif sistem beberapa kalimat sebelumnya. Dipikirkan lebih lanjut "bisa tampak aneh" lebih baik, jadi saya akan mengubah itu. Saya menyambut saran kata-kata lebih lanjut untuk membuatnya lebih jelas tanpa membuatnya terlalu bertele-tele.
mtraceur
2
Hal pertama yang saya diberitahu sebagai insinyur muda sehubungan dengan Unix adalah "Everything Is A File" dan saya bersumpah Anda bisa mendengar ibukota. Dan mendapatkan ide itu sejak awal membuat Unix / Linux tampak jauh lebih mudah dimengerti. Linux mewarisi sebagian besar filosofi desain itu. Saya senang seseorang menyebutkannya.
StephenG
2
@PeterCordes, DOS "memecahkan" masalah pengetikan dengan membuat nama file ajaib NULmuncul di setiap direktori, yaitu yang harus Anda ketikkan adalah > NUL.
Cristian Ciupitu
15

Saya pikir /dev/nulladalah 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.

pengguna5626466
sumber
10
Ini bukan hanya biaya setup, setiap penulisan ke dalam pipa memerlukan penyalinan memori, dan konteks beralih ke program membaca. (Atau setidaknya konteks beralih ketika penyangga pipa penuh. Dan pembaca harus melakukan salinan lain ketika readdatanya). Ini tidak dapat diabaikan pada single-core PDP-11 di mana Unix dirancang! Bandwidth memori / menyalin jauh lebih murah hari ini daripada saat itu. Sebuah writesistem panggilan ke FD terbuka pada /dev/nulldapat kembali segera tanpa membaca data dari buffer.
Peter Cordes
@PeterCordes, catatan saya bersifat tangensial, tetapi mungkin saja, secara paradoksal, memori yang ditulis hari ini lebih mahal dari sebelumnya. CPU 8-core berpotensi melakukan 16 operasi integer dalam waktu jam, sementara penulisan memori ujung-ke-ujung akan selesai misalnya dalam 16 jam (CPU 4GHz, RAM 250 MHz). Itulah faktor 256. RAM ke CPU modern seperti RL02 ke CPU PDP-11, hampir seperti unit penyimpanan periferal! :) Tidak sesederhana itu, secara alami, tetapi segala sesuatu yang mengenai cache akan ditulis, dan penulisan yang tidak berguna akan menghilangkan perhitungan lain dari ruang cache yang penting.
kkm
@ kkm: Ya, membuang sekitar 2 x 128kiB dari jejak L3 cache pada buffer pipa di kernel dan read buffer dalam nullprogram akan menyedot, tetapi kebanyakan CPU multi-core tidak berjalan dengan semua core sibuk sepanjang waktu, jadi Waktu CPU untuk menjalankan nullprogram 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 ...
Peter Cordes
.... Tetapi perhitungan memori Anda sangat cacat. CPU modern memiliki banyak paralelisme memori, jadi meskipun latensi ke DRAM adalah sekitar 200-400 siklus clock inti dan L3> 40, bandwidth adalah ~ 8 byte / jam. (Anehnya, bandwidth single-threaded ke L3 atau DRAM lebih buruk pada Xeon banyak-inti dengan memori quad-channel vs desktop quad-core, karena dibatasi oleh konkurensi maks permintaan yang dapat dipertahankan oleh satu core. Bandwidth = max_concurrency / latency: Mengapa Skylake jauh lebih baik daripada Broadwell-E untuk throughput memori single-threaded? )
Peter Cordes
... Lihat juga 7-cpu.com/cpu/Haswell.html untuk nomor Haswell yang membandingkan quad-core vs 18-core. Bagaimanapun, ya CPU modern bisa mendapatkan jumlah pekerjaan yang konyol per jam, jika mereka tidak terjebak menunggu memori. Angka Anda tampaknya hanya 2 operasi ALU per jam, seperti mungkin Pentium dari tahun 1993, atau ARM dua masalah modern kelas bawah. Ryzen atau Haswell berpotensi melakukan 4 skalar integer ALU ops + 2 ops memori per core per jam, atau jauh lebih dengan SIMD. misalnya Skylake-AVX512 memiliki (per core) throughput 2 per jam pada vpaddd zmm: 16 elemen 32-bit per instruksi.
Peter Cordes
7

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:

#include <unistd.h>
char buf[1024*1024];
int main() {
        while (read(0, buf, sizeof(buf)) > 0);
}

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).

% time dd if=/dev/zero bs=1M count=5000 |  ./nullread
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 9,33127 s, 562 MB/s
dd if=/dev/zero bs=1M count=5000  0,06s user 5,66s system 61% cpu 9,340 total
./nullread  0,02s user 3,90s system 41% cpu 9,337 total

sedangkan dengan /dev/nullredirection file standar, kami mendapatkan kecepatan yang jauh lebih baik (karena fakta-fakta yang disebutkan: kurang konteks switching, kernel hanya mengabaikan data daripada menyalinnya dll):

% time dd if=/dev/zero bs=1M count=5000 > /dev/null
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 1,08947 s, 4,8 GB/s
dd if=/dev/zero bs=1M count=5000 > /dev/null  0,01s user 1,08s system 99% cpu 1,094 total

(ini seharusnya menjadi komentar di sana, tetapi terlalu besar untuk itu dan benar-benar tidak dapat dibaca)

Matija Nalis
sumber
Perangkat keras apa yang Anda uji? 4.8GB / s cukup rendah dibandingkan dengan 23GB / s yang saya dapatkan pada Skylake i7-6700k (DDR4-2666, tetapi buffer harus tetap panas di cache L3. Jadi sebagian besar dari biaya adalah panggilan sistem menjadi mahal dengan Specter + Mitigasi Meltdown diaktifkan. Itu sakit dua kali lipat untuk perpipaan, karena penyangga pipa lebih kecil dari 1M, jadi itu panggilan sistem baca / baca lebih lanjut. Perbedaan perf hampir 10x lebih buruk daripada yang saya harapkan, pada sistem Skylake saya 23GB / s vs. 3.3GB / s , menjalankan x86-64 Linux 4.15.8-1-ARCH, jadi itu faktor 6.8. Wow, panggilan sistem mahal sekarang)
Peter Cordes
1
@PeterCordes 3GB / s dengan buffer pipa 64k menyarankan 2x 103124 syscalls per detik ... dan bahwa jumlah konteks switch, heh. Pada server cpu, dengan 200000 syscalls per detik, Anda mungkin mengharapkan ~ 8% overhead dari PTI, karena hanya ada sedikit set yang berfungsi. (Grafik yang saya referensikan tidak termasuk optimasi PCID, tapi mungkin itu tidak begitu signifikan untuk perangkat kerja kecil). Jadi saya tidak yakin PTI memiliki dampak besar di sana? brendangregg.com/blog/2018-02-09/...
sourcejedi
1
Oh, menarik, jadi itu adalah Silvermont dengan 2MB cache L2 , jadi ddbuffer 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. (Menurut stracepada desktop saya, writedan readmengembalikan 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)
Peter Cordes
1
@sourcejedi: Dengan mitigasi Specter diaktifkan, biaya syscallyang segera kembali ENOSYSadalah ~ 1800 siklus Skylake dengan mitigasi Specter diaktifkan, sebagian besar adalah wrmsryang 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).
Peter Cordes
1
@PeterCordes Pada sistem unix single-core, kita pasti akan melihat 1 konteks beralih per 64K, atau apa pun penyangga pipa Anda, dan itu akan merugikan ... sebenarnya saya juga melihat [jumlah konteks yang sama dengan 2 cpu core] ( unix.stackexchange.com/questions/439260/… ); itu juga harus menghitung siklus tidur / bangun untuk setiap 64k sebagai saklar konteks (ke "proses idle" nominal). Mempertahankan proses pipa pada cpu yang sama sebenarnya bekerja lebih dari dua kali lebih cepat.
sourcejedi
6

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:

$ echo -e 'foo\nbar\nbaz' | grep foo
foo

Dengan menggunakan proses substitusi Bash kita dapat mencapai hal yang sama melalui cara yang lebih bundaran:

$ grep foo <(echo -e 'foo\nbar\nbaz')
foo

Ganti grepuntuk echodan kita bisa lihat di bawah selimut:

$ echo foo <(echo -e 'foo\nbar\nbaz')
foo /dev/fd/63

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/fdadalah direktori ajaib yang membuat pipa bernama untuk setiap deskriptor file yang dimiliki oleh file yang mengaksesnya.

Kita bisa membuatnya kurang ajaib dengan mkfifomembuat pipa bernama yang muncul lsdan semuanya, seperti file biasa:

$ mkfifo foofifo
$ ls -l foofifo 
prw-rw-r-- 1 indigo indigo 0 Apr 19 22:01 foofifo
$ grep foo foofifo

Di tempat lain:

$ echo -e 'foo\nbar\nbaz' > foofifo

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.

Phil Frost
sumber
@ Gaya Ya? Lalu mengapa gema dicetak /dev/fd/63?
Phil Frost
Hm Poin bagus. Nah, ini diterapkan oleh shell, jadi mungkin shell Anda berbeda dari shell Bourne lama saya tumbuh bersama.
Lyle
Satu perbedaan adalah bahwa gema tidak membaca dari stdin, sementara grep melakukannya, tetapi saya tidak dapat berpikir bagaimana shell akan tahu itu sebelum mengeksekusi mereka.
Lyle
1
Dan strace membuat ini lebih jelas: bagi saya. Anda sudah benar, dengan bash. Konstruk '<(...)' melakukan sesuatu yang sangat berbeda dari <nama file. Hm Saya belajar sesuatu.
Lyle
0

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/nulltentu 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.

NickW
sumber
Ini terdengar seperti omong kosong. Menulis driver kernel bebas bug tidak lebih mudah daripada menulis program bebas bug yang bertuliskan + membuang stdin-nya. Itu tidak perlu setuid atau apa pun, jadi untuk keduanya /dev/nullatau program input-discarding yang diusulkan, vektor serangan akan sama: dapatkan skrip atau program yang berjalan sebagai root untuk melakukan sesuatu yang aneh (seperti mencoba lseekmasuk /dev/nullatau membuka beberapa kali dari proses yang sama, atau IDK apa. Atau memohon /bin/nulldengan lingkungan yang aneh, atau apa pun).
Peter Cordes
0

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/nullpanggilan 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.

Matthieu Moy
sumber
Mungkin saya seharusnya mengutarakannya lebih tepat. Maksud saya mengapa menerapkannya sebagai perangkat char bukan program. Akan ada beberapa baris yang baik tetapi implementasi program akan jelas lebih sederhana. Seperti yang ditunjukkan oleh jawaban lain, ada beberapa manfaat untuk ini; kepala efisiensi dan portabilitas di antara mereka.
Ankur S
Tentu. Saya baru saja menambahkan jawaban ini karena melihat implementasi aktual itu menyenangkan (saya baru-baru ini menemukannya sendiri), tetapi alasan sebenarnya adalah apa yang orang lain tunjukkan.
Matthieu Moy
Saya juga! Saya baru-baru ini mulai belajar perangkat di linux dan jawabannya cukup informatif
Ankur S
-2

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.

bermanfaat
sumber