Sospetto che il perché abbia molto a che fare con la visione / il design che ha plasmato Unix (e di conseguenza Linux) e i vantaggi che ne derivano.
Senza dubbio c'è un vantaggio non trascurabile in termini di prestazioni nel non avviare un processo aggiuntivo, ma penso che ci sia molto altro: Early Unix aveva una metafora "tutto è un file", che ha un vantaggio non ovvio ma elegante se si guarda dal punto di vista del sistema, piuttosto che dal punto di vista dello script di shell.
Supponi di avere il tuo null
programma da riga di comando e /dev/null
il nodo del dispositivo. Dal punto di vista della shell-scripting, il foo | null
programma è davvero utile e conveniente , e foo >/dev/null
richiede un po 'più di tempo per scrivere e può sembrare strano.
Ma ecco due esercizi:
Facciamo l'attuazione del programma null
utilizzando gli strumenti Unix esistenti e /dev/null
- facile: cat >/dev/null
. Fatto.
Puoi implementare /dev/null
in termini di null
?
Hai perfettamente ragione sul fatto che il codice C per scartare l'input sia banale, quindi potrebbe non essere ancora chiaro il motivo per cui è utile avere un file virtuale disponibile per l'attività.
Considera: quasi tutti i linguaggi di programmazione hanno già bisogno di lavorare con file, descrittori di file e percorsi di file, perché facevano parte del paradigma "tutto è un file" di Unix sin dall'inizio.
Se tutto ciò che hai sono programmi che scrivono su stdout, beh, al programma non importa se li reindirizzi in un file virtuale che ingoia tutte le scritture o una pipe in un programma che ingoia tutte le scritture.
Ora, se hai programmi che prendono percorsi di file per leggere o scrivere dati (cosa che la maggior parte dei programmi fa) - e vuoi aggiungere la funzionalità "input vuoto" o "scartare questo output" a quei programmi - beh, con /dev/null
quello viene gratis.
Si noti che l'eleganza di ciò è che riduce la complessità del codice di tutti i programmi coinvolti - per ogni caso d'uso comune ma speciale che il sistema può fornire come "file" con un "nome file" effettivo, il codice può evitare l'aggiunta di comandi personalizzati -line opzioni e percorsi di codice personalizzati da gestire.
Una buona ingegneria del software dipende spesso dalla ricerca di metafore buone o "naturali" per astrarre qualche elemento di un problema in un modo che diventa più facile da pensare ma rimane flessibile , in modo da poter risolvere sostanzialmente la stessa gamma di problemi di livello superiore senza dover dedicare costantemente tempo ed energie mentali alla reimplementazione di soluzioni agli stessi problemi di livello inferiore.
"Tutto è un file" sembra essere una tale metafora per accedere alle risorse: si chiama open
un determinato percorso in uno spazio dei nomi gerarchico, si ottiene un riferimento (descrittore di file) all'oggetto e si può read
e write
, ecc., Sui descrittori di file. Il tuo stdin / stdout / stderr sono anche descrittori di file che sono appena stati pre-aperti per te. Le tue pipe sono solo file e descrittori di file e il reindirizzamento dei file ti consente di incollare tutti questi pezzi insieme.
Unix ha avuto successo tanto quanto in parte grazie al modo in cui queste astrazioni hanno funzionato insieme, ed /dev/null
è meglio compreso come parte di tutto.
PS Vale la pena guardare la versione Unix di "tutto è un file" e cose come /dev/null
i primi passi verso una generalizzazione più flessibile e potente della metafora che è stata implementata in molti sistemi che seguirono.
Ad esempio, in Unix oggetti simili /dev/null
a file simili dovevano essere implementati nel kernel stesso, ma si scopre che è abbastanza utile esporre funzionalità in forma di file / cartella che da allora sono stati creati più sistemi che forniscono un modo per i programmi fare quello.
Uno dei primi è stato il sistema operativo Plan 9, realizzato da alcune delle stesse persone che hanno creato Unix. Più tardi, GNU Hurd ha fatto qualcosa di simile con i suoi "traduttori". Nel frattempo, Linux ha finito per ottenere FUSE (che ormai si è diffuso anche agli altri sistemi tradizionali).
cat foo | bar
è molto peggio (su larga scala) dibar <foo
.cat
è un programma banale, ma anche un programma banale crea costi (alcuni specifici per la semantica FIFO - perché i programmi non possono essere utilizzatiseek()
all'interno di FIFO, ad esempio un programma che potrebbe essere implementato in modo efficiente con la ricerca può finire per fare operazioni molto più costose quando viene data una pipeline; con un dispositivo a caratteri come/dev/null
questo può falsare quelle operazioni o con un file reale può implementarle, ma un FIFO non consente alcun tipo di gestione contestuale).