D'après ce que je comprends du programme IO, il y a stdin
, stdout
et stderr
flux de données (et un code de retour). stdout
et stderr
sont les deux flux de sortie de données. Donc, si j'utilise la redirection bash pour fermer l'un des flux de sortie, je peux déterminer le flux vers lequel le texte est envoyé. Droite?
J'utilise Ubuntu 18.04.1 LTS et je rencontre un problème étrange avec la redirection bash.
Laissez-moi vous expliquer l'exemple. Voici ma commande:
# apt-cache show php5
N: Can't select versions from package 'php5' as it is purely virtual
N: No packages found
# |
Le paquetage php5
n'existe pas sous Ubuntu 18.04, donc apt-cache
affiche une erreur. Je suppose que ce texte est envoyé au flux stderr
, alors j'ai essayé de fermer ce flux:
# apt-cache show php5 2>&-
# |
Il semble que cela vérifie que le texte a été envoyé via stderr
. Tout va bien jusqu'à présent! Mais maintenant, pour vérifier son intégrité, j'ai essayé de fermer stdout
(je devrais voir le texte de l'erreur maintenant):
# apt-cache show php5 1>&-
# |
Quoi!? J'ai redirigé stdout
cette fois, mais stderr
n'apparaît pas non plus?
Selon Internet, les descripteurs de fichier sont corrects: https://www.gnu.org/software/bash/manual/html_node/Redirections.html
Je ne peux pas comprendre ce qui pourrait se passer ici.
Capture d'écran:
TL; DR: Ce n'est pas bash
, c'est apt-cache
qui dérange avec les descripteurs de fichiers.
apt-cache
fait quelque chose de très intéressant - il a tendance à pas écrire des lignes commençant par N:
caractères destinés à stdout.
Considère ceci:
$ apt-cache show nonexistent
N: Unable to locate package nonexistent
E: No packages found
Nous voyons deux lignes, une commençant par N:
une commençant par E:
. N:
les lignes vont à stdout. Dans votre exemple, vous avez deux lignes N:
.
# apt-cache show php5
N: Can't select versions from package 'php5' as it is purely virtual
N: No packages found
Si vous suivez les appels système via strace -e write -f bash -c 'apt-cache show randomtext >&-'
, vous verrez que l'écriture de lignes E:
se produit, mais que les lignes N
n'y sont pas:
[pid 12450] write(2, "E", 1E) = 1
[pid 12450] write(2, ": ", 2: ) = 2
[pid 12450] write(2, "No packages found", 17No packages found) = 17
[pid 12450] write(2, "\n", 1
) = 1
[pid 12450] +++ exited with 100 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12450, si_uid=1000, si_status=100, si_utime=5, si_stime=2} ---
+++ exited with 100 +++
Donc, apt-cache
est suffisamment intelligent pour vérifier la sortie standard redirigée. Mais qu'en est-il de stderr
? Apparemment, les écritures sont toujours là: si vous faites strace -e write,openat,dup2 -f bash -c 'apt-cache show randomtext 2>&-
, vous verrez que apt-cache
ouvre /dev/null
pour qu'il reste encore quelque chose pour stderr
:
[pid 12543] openat(AT_FDCWD, "/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 2
....
[pid 12543] write(2, "N", 1) = 1
[pid 12543] write(2, ": ", 2) = 2
[pid 12543] write(2, "Unable to locate package randomt"..., 35) = 35
[pid 12543] write(2, "\n", 1) = 1
[pid 12543] write(2, "E", 1) = 1
[pid 12543] write(2, ": ", 2) = 2
[pid 12543] write(2, "No packages found", 17) = 17
[pid 12543] write(2, "\n", 1) = 1
[pid 12543] +++ exited with 100 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12543, si_uid=1000, si_status=100, si_utime=5, si_stime=3} ---
+++ exited with 100 +++
Si vous effectuez la même chose avec d'autres programmes dans bash, cela fonctionne comme prévu:
# stdout closed, stderr not
$ ls -l /proc/self/fd >&-
ls: write error: Bad file descriptor
# stdout open , stderr closed, and it's number is assigned to whatever command is trying to open - in this case /proc/self/fd directory
$ ls -l /proc/self/fd 2>&-
total 0
lrwx------ 1 xie xie 64 Oct 6 11:32 0 -> /dev/pts/1
lrwx------ 1 xie xie 64 Oct 6 11:32 1 -> /dev/pts/1
lr-x------ 1 xie xie 64 Oct 6 11:32 2 -> /proc/12723/fd