J'essaie de comprendre le concept de fichiers spéciaux sous Linux. Toutefois, /dev
à ma connaissance , avoir un fichier spécial dans le fichier semble tout à fait ridicule, alors que sa fonction pourrait être mise en œuvre par une poignée de lignes en C.
De plus, vous pouvez l'utiliser à peu près de la même manière, c.-à- null
d /dev/null
. Y a-t-il une raison spécifique de l'avoir en fichier? Faire un fichier ne cause pas beaucoup de problèmes comme trop de programmes accédant au même fichier?
files
devices
executable
null
Ankur S
la source
la source
cat foo | bar
est bien pire (à l'échelle) quebar <foo
.cat
est un programme trivial, mais même un programme trivial crée des coûts (certains d’entre eux sont spécifiques à la sémantique FIFO - car les programmes ne peuvent passeek()
entrer dans les FIFO, par exemple, un programme qui pourrait être mis en œuvre efficacement avec la recherche peut aboutir à des opérations beaucoup plus coûteuses lorsqu’un pipeline est créé, avec un périphérique de type caractère,/dev/null
il peut simuler ces opérations, ou avec un fichier réel, il peut les implémenter, mais une FIFO ne permet aucun type de traitement contextuel).grep blablubb file.txt 2>/dev/null && dosomething
ne pourrait pas fonctionner avec null étant un programme ou une fonction.read
fonction pour/dev/null
est composé d'un "retour 0" (ce qui signifie qu'il ne fait rien et que, je suppose, il en résulte un EOF): (De static github.com/torvalds/linux/blob/master/ drivers / char / mem.c )ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) { return 0; }
(Oh, je viens de voir que @JdeBP a déjà souligné ce point. En tout cas, voici l’illustration :-).Réponses:
Outre les avantages en termes de performances liés à l'utilisation d'un périphérique spécial caractères, le principal avantage est la modularité . / dev / null peut être utilisé dans presque tous les contextes dans lesquels un fichier est attendu, pas seulement dans les pipelines de shell. Considérez les programmes qui acceptent les fichiers en tant que paramètres de ligne de commande.
Ce sont tous des cas où l'utilisation d'un programme en tant que source ou puits serait extrêmement fastidieuse. Même dans le cas du pipeline shell, stdout et stderr peuvent être redirigés indépendamment vers des fichiers, ce qui est difficile à faire avec des exécutables en tant que récepteurs:
la source
/dev/null
uniquement les commandes du shell. Vous pouvez l'utiliser dans d'autres paramètres fournis à un logiciel, par exemple dans des fichiers de configuration. --- Fort le logiciel c'est très pratique. Il n'est pas nécessaire de faire la différence entre/dev/null
un fichier et un fichier normal.pipe
,fork
etexecve
comme toute autre tuyauterie de traitement, seulement avec des modifications auxdup2
appels qui établissent les connexions, non? Il est vrai la plupart des shells n'offrent pas les moyens de le faire plus jolies, mais sans doute si nous ne disposions pas tant que périphérique fichier modèle et la plupart des choses/dev
et/proc
ont été traités comme des executables, des obus aurait été conçu avec des moyens pour le faire aussi facilement que nous redirigeons maintenant.wait4
! Vous avez raison, il est certainement possible de diriger stdout et stderr vers différents programmes utilisant des apis POSIX, et il serait peut-être possible d'inventer une syntaxe de shell intelligente pour rediriger stdout et stderr vers différentes commandes. Cependant, je ne suis au courant d'aucun shell de ce type à l'heure actuelle, et le point le plus important est que / dev / null s'inscrit parfaitement dans les outils existants (qui fonctionne généralement avec des fichiers), et que / bin / null ne le ferait pas. Nous pourrions également imaginer une API IO qui permette à gcc de transférer aussi facilement (en toute sécurité!) Vers un programme que vers un fichier, mais ce n'est pas la situation dans laquelle nous nous trouvons.grep localhost /dev/ /etc/hosts 2> >(sed 's/^/STDERR:/' > errfile ) > >(sed 's/^/STDOUT:/' > outfile)
, le résultat est traité séparémenterrfile
etoutfile
En toute justice, ce n'est pas un fichier régulier en soi; c'est un dispositif spécial de personnage :
Son fonctionnement en tant que périphérique plutôt qu’en tant que fichier ou programme signifie qu’il est plus simple de rediriger ses entrées ou ses sorties, car il peut être attaché à n’importe quel descripteur de fichier, y compris les entrées / sorties / erreurs standard.
la source
cat file | null
aurait beaucoup de frais généraux, d' abord dans la mise en place d' un tuyau, fraie un processus, l' exécution de « nul » dans le nouveau processus, etc., aussinull
s'utiliseraient un peu de CPU dans un octets de lecture en boucle dans un tampon qui est plus tard juste mis au rebut ... La mise/dev/null
en oeuvre de dans le noyau est simplement plus efficace de cette façon. De plus, que se passe-t-il si vous souhaitez passer/dev/null
en argument, au lieu d'une redirection? (Vous pouvez utiliser<(...)
bash, mais c'est beaucoup plus lourd!)null
Au lieu d'utiliser la redirection vers/dev/null
, y aurait-il un moyen simple et clair de dire au shell d'exécuter un programme tout en envoyant simplement son stderr to null?/dev/zero
place.dd of=-
écrit dans un fichier appelé-
, omettez simplementof=
d’écrire sur stdout car c’est là que l’dd
écriture par défaut. Piping tofalse
ne fonctionnerait pas carfalse
il ne lisait pas son stdin, ildd
serait donc tué avec un SIGPIPE. Pour une commande qui supprime son entrée , vous pouvez utiliser ...cat > /dev/null
. De plus, la comparaison qui ne serait probablement pas pertinente en tant que goulot d'étranglement serait probablement la génération de nombres aléatoires ici.dd
etc. ne font même pas la peine de faire un appel système en écriture quand ils détectent que la destination est / dev / null.Je soupçonne que le pourquoi a beaucoup à faire avec la vision / conception qui a façonné Unix (et par conséquent Linux), et les avantages qui en découlent.
Nul doute qu’il ya un avantage non négligeable sur le plan des performances à ne pas créer un processus supplémentaire, mais je pense qu’il ya plus à faire: Early Unix avait une métaphore "tout est un fichier", ce qui présente un avantage non évident mais élégant si vous le regardez. cela du point de vue du système plutôt que du point de vue des scripts shell.
Supposons que vous ayez votre
null
programme de ligne de commande et/dev/null
le nœud de périphérique. Du point de vue des scripts shell, lefoo | null
programme est réellement utile et pratique , etfoo >/dev/null
prend un peu plus de temps à taper et peut sembler étrange.Mais voici deux exercices:
Nous allons mettre en œuvre le programme en
null
utilisant des outils Unix existants et/dev/null
- facile:cat >/dev/null
. Terminé.Pouvez-vous mettre
/dev/null
en œuvre en termes denull
?Vous avez absolument raison de dire que le code C destiné à supprimer une entrée est trivial, il est donc difficile de comprendre pourquoi il est utile de disposer d'un fichier virtuel pour la tâche.
Prenez en compte que presque tous les langages de programmation doivent déjà utiliser des fichiers, des descripteurs de fichiers et des chemins de fichiers, car ils faisaient partie du paradigme d'Unix "tout est un fichier" depuis le début.
Si tout ce que vous avez sont des programmes qui écrivent sur stdout, eh bien, le programme ne se soucie pas de les rediriger vers un fichier virtuel qui englobe toutes les écritures ou un canal vers un programme qui englobe toutes les écritures.
Maintenant, si vous avez des programmes qui utilisent des chemins de fichiers pour lire ou écrire des données (ce que font la plupart des programmes), et que vous souhaitez ajouter une fonctionnalité "entrée vide" ou "supprimer cette sortie" à ces programmes,
/dev/null
cela est gratuit.Notez que son élégance est de réduire la complexité du code de tous les programmes impliqués - pour chaque cas d'utilisation commun mais particulier que votre système peut fournir en tant que "fichier" avec un "nom de fichier" réel, votre code peut éviter d'ajouter une commande personnalisée. -ligne les options et les chemins de code personnalisés à gérer.
Une bonne ingénierie logicielle dépend souvent de la recherche de métaphores «naturelles» pour résumer certains éléments d’un problème d’une manière qui facilite la réflexion mais reste souple , de sorte que vous puissiez résoudre pratiquement le même éventail de problèmes de niveau supérieur sans avoir à consacrer temps et énergie mentale à réimplémenter en permanence des solutions aux mêmes problèmes de niveau inférieur.
« Tout est un fichier » semble être une telle métaphore pour l' accès aux ressources: Vous appelez
open
d'un chemin donné dans un espace de noms heirarchical, en obtenant une référence (descripteur de fichier) à l'objet, et vous pouvezread
etwrite
, etc sur les descripteurs de fichiers. Votre stdin / stdout / stderr sont également des descripteurs de fichier qui viennent d’être pré-ouverts pour vous. Vos canaux ne sont que des fichiers et des descripteurs de fichiers, et la redirection de fichiers vous permet de coller tous ces éléments ensemble.Unix a tout autant réussi en partie à cause de la manière dont ces abstractions ont bien fonctionné et
/dev/null
est mieux compris en tant que partie intégrante de cet ensemble.Post-scriptum Il convient de regarder la version Unix de "Tout est un fichier", entre autres,
/dev/null
comme les premiers pas vers une généralisation plus souple et plus puissante de la métaphore mise en œuvre dans de nombreux systèmes qui ont suivi.Par exemple, sous Unix, des objets spéciaux de type fichier, tels que ceux-ci,
/dev/null
devaient être implémentés dans le noyau lui-même, mais il s'avère assez utile d’exposer les fonctionnalités sous forme de fichier / dossier qui, depuis lors, ont permis de créer plusieurs systèmes qui permettent aux programmes pour faire ça.L'un des premiers était le système d'exploitation Plan 9, créé par les mêmes personnes qui ont créé Unix. Plus tard, GNU Hurd a fait quelque chose de similaire avec ses "traducteurs". Pendant ce temps, Linux finissait par obtenir FUSE (qui s’est également propagé aux autres systèmes traditionnels).
la source
NUL
apparaître le nom de fichier magique dans chaque répertoire, c’est-à-dire que tout ce que vous devez taper est> NUL
.Je pense
/dev/null
est un périphérique de caractère (qui se comporte comme un fichier ordinaire) au lieu d'un programme pour des raisons de performances .S'il s'agissait d'un programme, il faudrait charger, démarrer, planifier, exécuter, puis arrêter et décharger le programme. Le programme C simple que vous décrivez ne consomme évidemment pas beaucoup de ressources, mais je pense que cela fait une différence significative quand on considère un grand nombre (disons des millions) d’actions de redirection / canalisation, car les opérations de gestion de processus sont coûteuses à grande échelle, car ils impliquent des changements de contexte.
Autre hypothèse: la canalisation dans un programme nécessite que la mémoire alloue de la mémoire (même si elle est immédiatement supprimée). Donc, si vous dirigez dans l'outil, vous avez la double consommation de mémoire, une fois sur le programme d'envoi et à nouveau sur le programme de réception.
la source
read
les données). Ce n’est pas négligeable sur un PDP-11 monocœur où Unix a été conçu! La bande passante mémoire / copie est beaucoup moins chère aujourd'hui qu'elle ne l'était alors. Unwrite
appel système à une FD ouverte le/dev/null
peut revenir immédiatement sans même lire les données de la mémoire tampon.null
programme serait nul, mais la plupart des processeurs multicœurs ne fonctionnent pas avec tous les cœurs occupés en permanence. Le temps CPU pour exécuter lenull
programme est généralement gratuit. Sur un système avec tous les noyaux ancrés, une tuyauterie inutile est un plus gros problème. Mais non, un tampon "à chaud" peut être réécrit plusieurs fois sans passer à la RAM. Nous concourons donc principalement pour la bande passante L3, pas pour le cache. Pas génial, surtout sur un système SMT (hyperthreading) où d'autres noyaux logiques sur le même physique sont en compétition ...vpaddd zmm
: 16 éléments de 32 bits par instruction.En plus de "tout est un fichier" et donc de la facilité d'utilisation partout où la plupart des autres réponses sont basées, il y a aussi un problème de performances mentionné par @ user5626466.
Pour montrer en pratique, nous allons créer un programme simple appelé
nullread.c
:et compiler avec
gcc -O2 -Wall -W nullread.c -o nullread
(Remarque: nous ne pouvons pas utiliser lseek (2) sur les tuyaux, le seul moyen de drainer le tuyau consiste à le lire jusqu'à ce qu'il soit vide).
alors qu'avec
/dev/null
la redirection de fichiers standard , nous obtenons des vitesses bien meilleures (en raison des faits mentionnés: moins de changements de contexte, le noyau ignore simplement les données au lieu de les copier, etc.):(cela devrait être un commentaire là-bas, mais c'est trop gros pour ça et serait complètement illisible)
la source
dd
tampon + tampon de réception ne convient pas; vous avez probablement affaire à une bande passante en mémoire plutôt qu’à une bande passante en cache de dernier niveau. Vous pourriez obtenir une meilleure bande passante avec des buffers de 512k ou même de 64k. (strace
Sur mon bureau,write
etread
retournent 1048576, je pense donc que cela signifie que nous ne payons que le coût utilisateur du noyau <-> pour l'invalidation de TLB + le vidage de prédiction de branche une fois par MiB, et non par 64k, @sourcejedi. C'est Spectre ce qui a le plus coûté, je pense)syscall
retour immédiatENOSYS
est d'environ 1 800 cycles sur Skylake lorsque l'atténuation Specter est activée, la plupart d'entre eux étant l' invalidité dewrmsr
la BPU, selon les tests de @ BeeOnRope . Lorsque l'atténuation est désactivée, le temps d'aller-retour utilisateur-> noyau-> utilisateur est d'environ 160 cycles. Mais si vous êtes toucher beaucoup de mémoire, l' atténuation Meltdown est importante aussi. Hugepages devrait aider (moins d'entrées TLB doivent être rechargées).Votre question est posée comme si quelque chose serait gagné peut-être dans la simplicité en utilisant un programme nul à la place d'un fichier. Peut-être pourrions-nous nous débarrasser de la notion de "fichiers magiques" et utiliser à la place des "canaux ordinaires".
Mais considérons qu'un tuyau est aussi un fichier . Ils ne sont normalement pas nommés et ne peuvent donc être manipulés que par leurs descripteurs de fichier.
Considérez cet exemple quelque peu artificiel:
En utilisant la substitution de processus de Bash, nous pouvons accomplir la même chose de manière plus détournée:
Remplacez le
grep
pourecho
et on peut voir sous les couvertures:La
<(...)
construction est simplement remplacée par un nom de fichier, et grep pense que tout fichier ancien est ouvert, il se trouve que son nom est nommé/dev/fd/63
. Voici/dev/fd
un répertoire magique qui crée des canaux nommés pour chaque descripteur de fichier possédé par le fichier qui y accède.Nous pourrions faire moins de magie
mkfifo
en faisant un tuyau nommé qui apparaît dansls
et tout, comme un fichier ordinaire:Autre part:
et voici, grep va sortir
foo
.Je pense qu'une fois que vous avez compris que les pipes, les fichiers ordinaires et les fichiers spéciaux tels que / dev / null ne sont que des fichiers, il est évident que la mise en oeuvre d'un programme null est plus complexe. Le noyau doit gérer les écritures dans un fichier de toute façon, mais dans le cas de / dev / null, il peut simplement laisser tomber les écritures sur le sol, tandis qu'avec un tube il doit réellement transférer les octets vers un autre programme, qui doit ensuite effectivement les lire.
la source
/dev/fd/63
?Je dirais qu'il existe un problème de sécurité allant au-delà des paradigmes et des performances historiques. Limiter le nombre de programmes avec des informations d'identification d'exécution privilégiées, aussi simple soit-il, est un principe fondamental de la sécurité du système. Un remplaçant
/dev/null
serait certainement nécessaire pour disposer de tels privilèges en raison de son utilisation par les services du système. Les frameworks de sécurité modernes font un excellent travail de prévention des exploits, mais ils ne sont pas infaillibles. Un périphérique piloté par le noyau et accessible en tant que fichier est beaucoup plus difficile à exploiter.la source
/dev/null
ou un programme rejet d' entrée proposé, le vecteur d'attaque serait le même: obtenir un script ou un programme qui fonctionne en tant que root pour faire quelque chose de bizarre (comme essayer delseek
dans/dev/null
ou ouvrir plusieurs fois dans le même processus, ou IDK quoi, ou invoquer/bin/null
avec un environnement étrange, ou autre chose).Comme d'autres l'ont déjà souligné,
/dev/null
est un programme constitué d'une poignée de lignes de code. C'est juste que ces lignes de code font partie du noyau.Pour être plus clair, voici l’implémentation Linux: un périphérique caractère appelle des fonctions lorsqu’il est lu ou écrit. Écrire pour
/dev/null
appeler write_null , tout en lisant les appels read_null , enregistrés ici .Littéralement une poignée de lignes de code: ces fonctions ne font rien. Vous aurez besoin de plus de lignes de code que de doigts sur vos mains uniquement si vous comptez des fonctions autres que lire et écrire.
la source
J'espère que vous connaissez également le répertoire / dev / chargen / dev / zero et d’autres, comme / dev / null.
LINUX / UNIX en propose quelques-uns - mis à disposition pour que les utilisateurs puissent bien utiliser les fragments de code WELL WRITTEN CODE FrAGMEnTS.
Chargen est conçu pour générer un motif spécifique et répété de caractères - il est assez rapide et repousserait les limites des périphériques série et aiderait à déboguer les protocoles série écrits et ayant échoué à un test ou à un autre.
Zero est conçu pour peupler un fichier existant ou générer beaucoup de zéros.
/ dev / null est juste un autre outil avec la même idée en tête.
Tous ces outils de votre boîte à outils signifient que vous avez une chance sur deux de faire en sorte qu'un programme existant fasse quelque chose d'unique, indépendamment de son (votre besoin spécifique) en tant que périphériques ou fichiers de remplacement.
Permet de mettre en place un concours pour voir qui peut produire le résultat le plus excitant compte tenu du nombre limité de périphériques de personnage dans votre version de LINUX.
la source