2011-05-04 8 views
4

Dans Mark Sobell Un Guide pratique des commandes Linux, éditeurs et programmation Shell, deuxième édition il écrit (p 432).:exec n <& m par rapport exec n> & m - basé sur le livre Linux Sobell

Le jeton < & duplique un descripteur de fichier d'entrée ; > & duplique un descripteur de fichier de sortie .

Cela semble être incompatible avec une autre déclaration sur la même page:

Utilisez le format suivant pour ouvrir ou redirect descripteur de fichier n en double de descripteur de fichier m:

Exécuter n < & m

et avec un exemple également sur le même page:

# File descriptor 3 duplicates standard input 
# File descriptor 4 duplicates standard output 
exec 3<&0 4<&1 

Si> & doublons un descripteur de fichier de sortie alors devrait-on pas dire

exec 4>&1 

à dupliquer la sortie standard?

Répondre

8

L'exemple est juste dans la pratique. L'explication originale du livre est une description précise de ce que dit la norme POSIX, mais les shells de type POSIX que j'ai à portée de main (bash et dash, les seuls que l'on voit souvent sous Linux) ne sont pas si pointilleux.

La norme POSIX says the same thing as the book sur les entrées et les descripteurs de sortie, et poursuit en disant ceci: pour n<&word, « si les chiffres word ne représentent pas un descripteur de fichier déjà ouvert pour l'entrée, une erreur de redirection entraîne ». Donc, si vous voulez faire attention à la compatibilité POSIX, vous devriez éviter cette utilisation. La documentation bash également says the same thing environ <& et >&, mais sans la promesse d'une erreur. Ce qui est bien, car cela ne donne pas d'erreur. Au lieu de cela, empiriquement n<&m et n>&m semblent être interchangeables. La seule différence entre <& et >& est que si vous laissez le numéro fd à gauche, <& est par défaut à 0 (stdin) et >& à 1 (stdout).

Par exemple, nous allons commencer une coquille avec fd 1 pointant vers un fichier bar, puis essayer exactement le exec 4<&1 exemple, essayez d'écrire sur le fd résultant 4, et voir si cela fonctionne:

$ sh -c 'exec 4<&1; echo foo >&4' >bar; cat bar 
foo 

C'est le cas, et cela vaut en utilisant soit dash ou bash (ou bash --posix) pour le shell.

Sous le capot, ce sens parce que < & et> & sont presque certainement appeler juste dup2(), qui ne se soucie pas de savoir si les fds sont ouverts pour la lecture ou l'écriture ou annexant ou quoi.

[EDIT : Ajout d'une référence à Posix après discussion dans les commentaires.]

+0

+1, génial à savoir! – l0b0

+0

Merci, surtout pour la référence. Je suis plus intéressé par ce qui est censé fonctionner que par ce qui peut parfois fonctionner dans la pratique. –

+0

@Alexandros: Assez juste. En regardant le standard POSIX (http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_07_05), qui est une interprétation de "supposé fonctionner", il dit pour "n <& word' que" si les chiffres de 'word' ne représentent pas un descripteur de fichier déjà ouvert, une erreur de redirection doit se produire". Donc, si vous voulez faire attention à la compatibilité POSIX, vous devriez éviter cette utilisation. –

2

Si stdout est un TTY, il peut en toute sécurité être cloné pour la lecture ou l'écriture. Si stdout est un fichier, cela peut ne pas fonctionner. Je pense que l'exemple devrait être 4>&1. Je suis d'accord avec Greg que vous pouvez lire et écrire le descripteur de clone, mais demander une redirection avec <& est censé être fait avec des descripteurs source qui sont lisibles, et attendre que stdout soit lisible n'a pas de sens. (Bien que je reconnaisse que je n'ai pas de référence pour cette revendication.)

Un exemple peut le rendre plus clair. Avec ce script:

#!/bin/bash 

exec 3<&0 
exec 4<&1 

read -p "Reading from fd 3: " <&3 
echo From fd 3: $REPLY >&2 
REPLY= 
read -p "Reading from fd 4: " <&4 
echo From fd 4: $REPLY >&2 

echo To fd 3 >&3 
echo To fd 4 >&4 

Je reçois la sortie suivante (la substance après: sur « Lecture de » lignes tapés au terminal):

$ ./5878384b.sh 
Reading from fd 3: foo 
From fd 3: foo 
Reading from fd 4: bar 
From fd 4: bar 
To fd 3 
To fd 4 
$ ./5878384b.sh < /dev/null 
From fd 3: 
Reading from fd 4: foo 
From fd 4: foo 
./5878384b.sh: line 12: echo: write error: Bad file descriptor 
To fd 4 
$ ./5878384b.sh > /dev/null 
Reading from fd 3: foo 
From fd 3: foo 
./5878384b.sh: line 9: read: read error: 0: Bad file descriptor 
From fd 4: 
To fd 3 
+0

Il n'est pas immédiatement clair d'où viennent "foo" et "bar". C'est un bon exemple, mais peut-être serait plus clair si vous appeliez le script "printf 'foo \ nbar \ n' | ./5878384.sh" –

+0

Merci pour les commentaires. Je penche pour votre point de vue, mais j'espérais une référence spécifique (par exemple à la norme POSIX). Je suis surpris du peu de matériel faisant autorité sur les descripteurs de fichiers exec et de fichiers. –

+0

@William le piping dedans ne fonctionne pas, puisque le tuyau va seulement à stdin, mais j'ai essayé de clarifier quelles parties sont entrées/sorties. Merci pour la suggestion. – Andy

0

esprit la différence entre les descripteurs de fichiers et les flux IO tels que stderr et stdout.

Les opérateurs de redirection ne font que rediriger les flux IO via différents descripteurs de fichiers (mécanismes de gestion de flux IO); ils n'effectuent aucune copie ou duplication des flux d'E/S (c'est ce à quoi sert tee (1)).

Voir: File Descriptor 101

Un autre test pour montrer que n < & m et n> & m sont interchangeables serait « d'utiliser soit le style de 'n < & -' ou 'n> & -' pour la fermeture un descripteur de fichier, même s'il ne correspond pas au mode lecture/écriture avec lequel le descripteur de fichier a été ouvert "(http://www.gnu.org/s/hello/manual/autoconf/File-Descriptors.html).