Je tentais de rediriger les deux stdout
et stderr
à un jour fichier, et je suis tombé sur ceci:
<command> > file.txt 2>&1
Apparemment, cette redirection stderr
vers d’ stdout
abord, puis le résultat stdout
est redirigé vers file.txt
.
Cependant, pourquoi n'est pas la commande <command> 2>&1 > file.txt
? On pourrait naturellement lire ceci comme (en supposant une exécution de gauche à droite) la commande étant exécutée en premier, la stderr
redirection vers stdout
, puis lastdout
écriture enfile.txt
. Mais ce qui précède ne fait que rediriger stderr
vers l'écran.
Comment le shell interprète-t-il les deux commandes?
command-line
bash
redirect
Train Heartnet
la source
la source
bash
manuel . Au fait, les redirections ne sont pas des commandes.execv
appel -family syscall est appelé pour effectivement transférer le sous-processus à la commande en cours de démarrage, le shell est alors hors de la boucle (le code ne s'exécute plus dans ce processus) ) et n’a aucun moyen de contrôler ce qui se passe à partir de ce moment; Les redirections doivent donc toutes être effectuées avant le début de l'exécution, alors que le shell a une copie de lui-même en cours d'exécution dans le processusfork()
pour exécuter votre commande.Réponses:
Lorsque vous exécutez
<command> 2>&1 > file.txt
stderr, celui-ci est redirigé2>&1
vers l’emplacement actuel de stdout, votre terminal. Après cela, stdout est redirigé vers le fichier par>
, mais stderr n’est pas redirigé avec lui, reste donc comme sortie terminal.Avec
<command> > file.txt 2>&1
stdout, il est d'abord redirigé vers le fichier>
, puis2>&1
redirige stderr vers la destination de stdout, à savoir le fichier.Cela peut sembler contre-intuitif au début, mais quand vous pensez aux redirections de cette façon, et souvenez-vous qu’elles sont traitées de gauche à droite, cela a beaucoup plus de sens.
la source
Cela peut avoir un sens si vous le tracez.
Au début, stderr et stdout vont à la même chose (généralement le terminal, que j'appelle ici
pts
):Je fais référence à stdin, stdout et stderr par leur numéro de descripteur de fichier : il s’agit des descripteurs de fichier 0, 1 et 2 respectivement.
Maintenant, dans le premier ensemble de redirections, nous avons
> file.txt
et2>&1
.Alors:
> file.txt
:fd/1
va maintenant àfile.txt
. Avec>
,1
est le descripteur de fichier implicite lorsque rien n'est spécifié, c'est donc1>file.txt
:2>&1
:fd/2
va maintenant où quefd/1
ce soit actuellement :Par contre, avec
2>&1 > file.txt
, l'ordre étant inversé:2>&1
:fd/2
va maintenant où quefd/1
ce soit, ce qui signifie que rien ne change:> file.txt
:fd/1
va maintenant àfile.txt
:Le point important est que la redirection ne signifie pas que le descripteur de fichier redirigé suivra toutes les modifications ultérieures apportées au descripteur de fichier cible; il ne prendra que l' état actuel .
la source
2.
la deuxième partie;fd/1 -> file.txt
et nonfd/2 -> file.txt
.Je pense qu'il est utile de penser que le shell va d'abord configurer la redirection à gauche et la terminer avant de configurer la redirection suivante.
La ligne de commande Linux de William Shotts dit
cela a du sens, mais alors
mais en réalité, nous pouvons rediriger stdout vers stderr après avoir redirigé stderr vers un fichier avec le même effet
Donc, dans
command > file 2>&1
, le shell envoie stdout à un fichier, puis envoie stderr à stdout (qui est en train d'être envoyé à un fichier). Alors que danscommand 2>&1 > file
le shell, redirige d’abord stderr vers stdout (c’est-à-dire qu’il l’affiche dans le terminal où stdout se trouve normalement), puis redirige ensuite stdout vers le fichier. TLCL est trompeur en disant que nous devons d'abord rediriger stdout: puisque nous pouvons tout d'abord rediriger stderr vers un fichier, puis lui envoyer stdout. Ce que nous ne pouvons pas faire, c'est de rediriger stdout vers stderr ou vice versa avant la redirection vers un fichier. Un autre exempleOn pourrait penser que cela laisserait stdout au même endroit que stderr, mais ce n’est pas le cas, il redirige stdout vers stderr (l’écran) d’abord, puis ne redirige que stderr, comme lorsque nous l’avons essayé à l’inverse ...
J'espère que cela apporte un peu de lumière ...
la source
Vous avez déjà quelques très bonnes réponses. Permettez-moi de souligner cependant que deux concepts différents sont en jeu, dont la compréhension aide énormément:
Arrière-plan: descripteur de fichier et table de fichiers
Votre descripteur de fichier est juste un nombre 0 ... n, qui correspond à l'index de la table des descripteurs de fichier de votre processus. Par convention, STDIN = 0, STDOUT = 1, STDERR = 2 (notez que les termes,
STDIN
etc. ne sont ici que des symboles / macros utilisés par convention dans certains langages de programmation et pages de manuel, il n’existe pas d’objet "réel" appelé STDIN; le but de cette discussion, STDIN est 0, etc.).Cette table de descripteur de fichier en elle-même ne contient aucune information sur la nature du fichier. Au lieu de cela, il contient un pointeur sur une autre table de fichiers; ce dernier contient des informations sur un fichier physique réel (ou un périphérique bloc, ou un canal, ou tout autre élément que Linux peut adresser via le mécanisme de fichier), ainsi que des informations supplémentaires (que ce soit en lecture ou en écriture).
Ainsi, lorsque vous utilisez
>
ou<
dans votre shell, vous remplacez simplement le pointeur du descripteur de fichier respectif pour désigner autre chose. La syntaxe2>&1
pointe simplement le descripteur 2 sur 1 où.> file.txt
s'ouvre simplementfile.txt
pour l'écriture et laisse STDOUT (le descripteur de fichier 1) pointer vers cela.Il y a d'autres goodies, par exemple
2>(xxx)
(ex: créer un nouveau processus en cours d'exécutionxxx
, créer un canal, connecter le descripteur de fichier 0 du nouveau processus à la fin de la lecture du canal et connecter le descripteur de fichier 2 du processus original à la fin de l’écriture du processus). tuyau).C’est aussi la base de la "magie du traitement de fichier" dans un logiciel autre que votre shell. Par exemple, vous pouvez, dans votre script Perl,
dup
convertir le descripteur de fichier STDOUT en un autre (temporaire), puis rouvrir STDOUT dans un fichier temporaire nouvellement créé. À partir de ce moment, toutes les sorties STDOUT de votre propre script Perl et tous lessystem()
appels de ce script se retrouveront dans ce fichier temporaire. Lorsque vous avez terminé, vous pouvez rétablirdup
votre STDOUT dans le descripteur temporaire dans lequel vous l'avez enregistré, et tout est comme avant. Vous pouvez même écrire dans ce descripteur temporaire entre-temps. Ainsi, si votre sortie réelle de STDOUT est dirigée vers le fichier temporaire, vous pouvez toujours générer des éléments dans le vrai STDOUT (généralement, l'utilisateur).Répondre
Pour appliquer les informations de base données ci-dessus à votre question:
De gauche à droite.
fork
hors d'un nouveau processus.file.txt
et stockez son pointeur dans le descripteur de fichier 1 (STDOUT).file.txt
).exec
le<command>
Cela aurait du sens s'il n'y avait qu'une seule table, mais comme expliqué ci-dessus, il y en a deux. Les descripteurs de fichier ne se pointent pas de manière récursive, cela n'a aucun sens de penser "rediriger STDERR vers STDOUT". La bonne idée est de "pointer STDERR vers tous les points de STDOUT". Si vous changez de STDOUT plus tard, STDERR reste en place, il ne va pas comme par magie avec les modifications ultérieures apportées à STDOUT.
la source
L'ordre est de gauche à droite. Le manuel de Bash a déjà couvert ce que vous demandez. Citation de la
REDIRECTION
section du manuel:et quelques lignes plus tard:
Il est important de noter que la redirection est résolue avant toute commande! Voir https://askubuntu.com/a/728386/295286
la source
C'est toujours laissé à droite ... sauf quand
Comme en mathématiques, nous allons de gauche à droite, sauf que la multiplication et la division sont effectuées avant l'addition et la soustraction, sauf que les opérations entre parenthèses (+ -) sont effectuées avant la multiplication et la division.
Selon le guide pour débutants Bash ici ( Guide pour débutants Bash ), il existe 8 ordres de hiérarchie de ce qui vient en premier (avant gauche à droite):
Donc ça reste toujours à droite ... sauf quand ...
la source