Pourquoi est-ce $ ls > ls.out
que 'ls.out' est inclus dans la liste des noms de fichiers dans le répertoire courant? Pourquoi cela a-t-il été choisi? Pourquoi pas autrement?
command-line
bash
redirect
Edward Torvalds
la source
la source
ls > ../ls.out
Réponses:
Lors de l'évaluation de la commande, la
>
redirection est résolue en premier: ainsi, au moment de l'ls
exécution, le fichier de sortie a déjà été créé.C'est également la raison pour laquelle la lecture et l'écriture dans le même fichier à l'aide d'une
>
redirection dans la même commande tronque le fichier; au moment où la commande s'exécute, le fichier a déjà été tronqué:Astuces pour éviter cela:
<<<"$(ls)" > ls.out
(fonctionne pour toute commande devant être exécutée avant la résolution de la redirection)La substitution de commande est exécutée avant l'évaluation de la commande externe, elle
ls
est donc exécutée avant sals.out
création:ls | sponge ls.out
(fonctionne pour toute commande devant être exécutée avant la résolution de la redirection)sponge
écrit dans le fichier uniquement lorsque le reste du canal a terminé son exécution, ills
est donc exécuté avant sals.out
création (sponge
est fourni avec lemoreutils
package):ls * > ls.out
(fonctionne pourls > ls.out
le cas spécifique de)L'extension du nom de fichier est effectuée avant que la redirection ne soit résolue, donc
ls
s'exécutera sur ses arguments, qui ne contiendront pasls.out
:Sur la raison pour laquelle les redirections sont résolues avant l'exécution du programme / script / quoi que ce soit, je ne vois pas de raison spécifique pour laquelle il est obligatoire de le faire, mais je vois deux raisons pour lesquelles il vaut mieux le faire:
ne pas rediriger STDIN au préalable ferait en sorte que le programme / script / que ce soit soit bloqué jusqu'à ce que STDIN soit redirigé;
ne pas rediriger STDOUT au préalable devrait nécessairement faire du tampon shell la sortie du programme / script / quoi que ce soit jusqu'à ce que STDOUT soit redirigé;
Donc une perte de temps dans le premier cas et une perte de temps et de mémoire dans le second cas.
C'est juste ce qui me vient à l'esprit, je ne prétends pas que ce sont les raisons réelles; mais je suppose que dans l'ensemble, si on avait le choix, ils iraient avec redirection avant de toute façon pour les raisons susmentionnées.
la source
De
man bash
:La première phrase suggère que la sortie est faite pour aller ailleurs
stdin
qu'avec la redirection juste avant l'exécution de la commande. Ainsi, pour être redirigé vers un fichier, le fichier doit d'abord être créé par le shell lui-même.Pour éviter d'avoir un fichier, je vous suggère de rediriger la sortie vers le canal nommé d'abord, puis vers le fichier. Notez l'utilisation de
&
pour rendre le contrôle du terminal à l'utilisateurMais pourquoi?
Pensez-y - où sera la sortie? Un programme a des fonctions comme
printf
,sprintf
,puts
, tous par défaut aller àstdout
, mais peut leur sortie être allé fichier si le fichier n'existe pas en premier lieu? C'est comme de l'eau. Pouvez-vous obtenir un verre d'eau sans mettre le verre sous le robinet en premier?la source
Je ne suis pas en désaccord avec les réponses actuelles. Le fichier de sortie doit être ouvert avant l'exécution de la commande, sinon la commande n'aura aucun endroit pour écrire sa sortie.
En effet, «tout est un fichier» dans notre monde. La sortie à l'écran est SDOUT (aka descripteur de fichier 1). Pour qu'une application écrive sur le terminal, elle ouvre fd1 et y écrit comme un fichier.
Lorsque vous redirigez la sortie d'une application dans un shell, vous modifiez fd1 afin qu'il pointe réellement vers le fichier. Lorsque vous dirigez, vous modifiez le STDOUT d'une application pour devenir le STDIN d'une autre (fd0).
Mais c'est bien de le dire, mais vous pouvez très facilement voir comment cela fonctionne
strace
. C'est assez lourd mais cet exemple est assez court.À l'intérieur,
strace.out
nous pouvons voir les faits saillants suivants:Cela s'ouvre
ls.out
commefd3
. Écris seulement. Tronque (remplace) s'il existe, sinon crée.C'est un peu de jonglage. Nous shuntons STDOUT (fd1) à fd10 et le fermons. C'est parce que nous ne sortons rien vers le vrai STDOUT avec cette commande. Il termine en dupliquant la poignée d'écriture
ls.out
et en fermant la poignée d' origine.Il s'agit de rechercher l'exécutable. Une leçon peut-être pour ne pas avoir un long chemin;)
Ensuite, la commande s'exécute et le parent attend. Au cours de cette opération, n'importe quel STDOUT aura effectivement été mappé sur le descripteur de fichier ouvert
ls.out
. Lorsque l'enfant émetSIGCHLD
, cela indique au processus parent qu'il est terminé et qu'il peut reprendre. Il se termine par un peu plus de jonglage et une fin dels.out
.Pourquoi y a-t-il tant de jonglage? Non, je ne suis pas tout à fait sûr non plus.
Bien sûr, vous pouvez modifier ce comportement. Vous pouvez mettre en mémoire tampon quelque chose comme
sponge
et cela sera invisible à partir de la commande en cours. Nous affectons toujours les descripteurs de fichiers, mais pas de manière visible par le système de fichiers.la source
Il y a aussi un bel article sur la mise en œuvre des opérateurs de redirection et de pipe dans le shell . Ce qui montre comment la redirection pourrait être implémentée et
$ ls > ls.out
pourrait ressembler à ceci :la source