Lorsque vous redirigez une liste de commandes contenant une redirection exec, l'exec> / dev / null ne semble pas être appliqué par la suite, comme avec:
{ exec >/dev/null; } >/dev/null; echo "Hi"
"Salut" est imprimé.
J'avais l'impression que la {}
liste de commandes n'est pas considérée comme un sous-shell à moins qu'elle ne fasse partie d'un pipeline, donc elle exec >/dev/null
devrait toujours être appliquée dans l'environnement shell actuel dans mon esprit.
Maintenant, si vous le changez en:
{ exec >/dev/null; } 2>/dev/null; echo "Hi"
il n'y a pas de sortie comme prévu; le descripteur de fichier 1 reste également pointé sur / dev / null pour les futures commandes. Cela est illustré par la réexécution:
{ exec >/dev/null; } >/dev/null; echo "Hi"
qui ne donnera aucune sortie.
J'ai essayé de créer un script et de le structurer, mais je ne sais toujours pas exactement ce qui se passe ici.
À chaque étape de ce script, qu'arrive-t-il au descripteur de fichier STDOUT?
EDIT: Ajout de ma sortie strace:
read(255, "#!/usr/bin/env bash\n{ exec 1>/de"..., 65) = 65
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD) = 0
fcntl(1, F_DUPFD, 10) = 10
fcntl(1, F_GETFD) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 1) = 1
close(3) = 0
close(10) = 0
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD) = 0
fcntl(1, F_DUPFD, 10) = 10
fcntl(1, F_GETFD) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 1) = 1
close(3) = 0
dup2(10, 1) = 1
fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
fstat(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, TCGETS, 0x7ffee027ef90) = -1 ENOTTY (Inappropriate ioctl for device)
write(1, "hi\n", 3) = 3
la source
close(10)
. Pouvez-vous également publier l'intégralité du contenu de votre script sur lequel vous avez exécuté Strace?;
après}
, ce qui change le sens de> /dev/null
ne pas s'appliquer à la liste composée{}
après tout.Réponses:
Suivons
pas à pas.
Il existe deux commandes:
une.
{ exec >/dev/null; } >/dev/null
, suivi parb.
echo "Hi"
Le shell exécute d'abord la commande (a) puis la commande (b).
L'exécution du
{ exec >/dev/null; } >/dev/null
produit se déroule comme suit:une. Tout d'abord, le shell effectue la redirection
>/dev/null
et se souvient de l'annuler à la fin de la commande .b. Ensuite, le shell s'exécute
{ exec >/dev/null; }
.c. Enfin, le shell ramène la sortie standard à son emplacement d'origine. (Il s'agit du même mécanisme que dans
ls -lR /usr/share/fonts >~/FontList.txt
- les redirections sont effectuées uniquement pour la durée de la commande à laquelle elles appartiennent.)Une fois la première commande effectuée, le shell s'exécute
echo "Hi"
. La sortie standard est là où elle était avant la première commande.la source
Afin de ne pas utiliser de sous-shell ou de sous-processus, lorsque la sortie d'une liste composée
{}
est canalisée>
, le shell enregistre le descripteur STDOUT avant d'exécuter la liste composée et le restaure après. Ainsi,exec >
dans la liste composée ne porte pas son effet au-delà du point où l'ancien descripteur est rétabli en tant que STDOUT.Jetons un coup d'œil à la partie pertinente de
strace bash -c '{ exec >/dev/null; } >/dev/null; echo hi' 2>&1 | cat -n
:Vous pouvez voir comment, à la ligne 134, descriptor
1
(STDOUT
) est copié sur un autre descripteur avec index au moins10
(c'est ce quiF_DUPFD
fait; il retourne le descripteur disponible le plus bas en commençant au nombre donné après la duplication sur ce descripteur). Voyez également comment, à la ligne 137, le résultat deopen("/dev/null")
(descriptor3
) est copié dans descriptor1
(STDOUT
). Enfin, en ligne147
, l'ancienSTDOUT
descripteur enregistré sur10
est recopié sur descriptor1
(STDOUT
). L'effet net est d'isoler le changement enSTDOUT
ligne144
(ce qui correspond à l'intérieurexec >/dev/null
).la source
exec
.La différence entre
{ exec >/dev/null; } >/dev/null; echo "Hi"
et{ exec >/dev/null; }; echo "Hi"
est que la double redirection faitdup2(10, 1);
avant de fermer fd 10 qui est la copie de l'originalstdout
, avant d'exécuter la commande suivante (echo
).Cela se produit de cette façon car la redirection externe recouvre en fait la redirection interne. C'est pourquoi il copie le
stdout
fd original une fois terminé.la source