Est-ce que la coquille fourche lorsque j'utilise des commands embeddedes?

Quand j'exécute le type type command, cela me donne un résultat à la sortie standard.

Donc, maintenant j'essaie cette command:

 type type > abc.txt 

Il redirige la sortie standard vers abc.txt . Donc, si cette command s'exécute sur le même process (bash lui-même), alors le descripteur de file 1 pointe vers abc.txt . Après cela, chaque fois que j'utilise une command, ces résultats devraient aller au file abc.txt , car le descripteur de file 1 pointe vers abc.txt .

Cependant, les résultats vont toujours à la sortie standard. Cela signifie-t-il que les shell-ins s'exécutent sous un process fourchu?

Redirection de sortie

Le descripteur de file 1 représente stdout , le stream de sortie standard. Lorsque la redirection de sortie est utilisée dans le type type > abc.txt , le shell ouvre le file abc.txt pour l'écriture et le descripteur de file 1 est modifié de sorte qu'il pointe vers le file ouvert au lieu du terminal.

Cependant, cette redirection ne s'applique qu'à la command en cours d'exécution, de sorte que cela n'implique pas que la command s'exécute dans un process (ou un sous-shell) fourchu.

Redirection persistante

Si vous souhaitez que la redirection persiste, vous pouvez utiliser le shell exec embedded pour modifier les descripteurs de file, par exemple pour redirect la sortie standard pour les commands successives, exécutez la command suivante.

 exec >abc.txt 

Soyez prudent en exécutant ceci car votre session shell sera difficile à utiliser si toutes les sorties de la command sont redirigées vers un file au lieu de votre terminal. Vous pouvez restaurer le descripteur de file stdout sur le périphérique de sortie du terminal en le redirigeant vers le même périphérique pointé par stderr (descripteur de file 2 ):

 exec >&2 

Ressources connexes

Pour plus de détails, voir:

  • la section sur les Redirections du manuel Bash
  • Entrée et sortie du Wiki de Greg
  • Didacticiel de redirection de Bash-hackers Wiki
  • l'article de Wikipédia sur la redirection
  • le descripteur de file article Wikipédia

Normalement, pour redirect une command, tout ce que le shell doit faire est de fourrer un process enfant, de faire la redirection dans l'enfant uniquement (les descripteurs de files parents ne sont pas affectés) puis d'exécuter la command le parent attend juste l'enfant).

Pour les commands embeddedes (ou commands composées, ou fonctions …), il n'y a ni fork ni exec. Cependant, après la fin d'une command embeddede redirigée, les descripteurs de files reviennent à leur état antérieur.

Pour ce faire, le shell enregistre juste une copy du descripteur de file redirigé vers un autre descripteur de file avant d'effectuer la redirection, marque ce descripteur de file avec l'indicateur O_CLOEXEC (dans le cas où le builtin finit par exécuter une command comme eval ou command ) lorsque le builtin returnne, le shell restaure le descripteur de file.

Vous pouvez voir que si vous exécutez par exemple:

 strace sh -c 'echo test > /dev/null; :' 

Vous verrez (seules les inputs pertinentes sont incluses):

  • open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 : ouvre le file à redirect vers.
  • fcntl(1, F_DUPFD, 10) = 10 : duplique le stdout original au premier fd> = 10 (ici 10) disponible.
  • fcntl(10, F_SETFD, FD_CLOEXEC) = 0 : définissez le drapeau O_CLOEXEC dessus
  • dup2(3, 1) = 1 : rend le file redirigé stdout
  • close(3) = 0 : n'est plus nécessaire
  • write(1, "test\n", 5) = 5 : echo s'exécute et écrit "test \ n" sur son stdout (maintenant redirigé vers / dev / null).
  • dup2(10, 1) = 1 : restore stdout
  • close(10) = 0 : fermer fd 10 n'est plus nécessaire.

Notez que dans le shell Bourne, redirect une command composée a provoqué une fourchette (comme dans a=0; { a=1; echo "$a"; } >&2; echo "$a" donnerait 1 puis 0 ). Pour contourner cela, vous avez effectivement dû faire ce qui précède à la main:

Au lieu de

 while cmd1; do cmd2; i=`expr "$i" + 1`; done > file 

Tu devais faire:

 exec 3>&1 > file while cmd1 3>&-; do cmd2 3>&-; i=`expr "$i" + 1 3>&-`; done exec >&3 3>&- 

(avec un 3>&- pour chaque command car ce fd n'a pas le drapeau O_CLOEXEC).

Et dans les premières versions du shell Bourne, vous ne pouviez pas redirect les builtins. Sur un Unix V7 sur un pdp11 émulé:

 $ eval a=1 > /tmp/x illegal io $ read a < /etc/passwd illegal io 

Dès que la command est terminée, les files d'input sont fermés, ce qui permet leur écriture par d'autres process, le descripteur de file est libéré et le process fils est terminé.