Lorsque le fichier d'entrée est recherché (comme la lecture d'un fichier normal) ou non recherché (comme la lecture d'un tuyau), sed
(et d'autres utilitaires standard) se comporteront différemment ( INPUT FILES
section Lire de ce lien ).
Citation du doc:
Lorsqu'un utilitaire standard lit un fichier d'entrée recherché et se termine sans erreur avant d'atteindre la fin du fichier, l'utilitaire doit s'assurer que l'offset de fichier dans la description du fichier ouvert est correctement positionné juste après le dernier octet traité par l'utilitaire.
Donc dans:
(sed '/y/ q'; echo aaa; cat) < test
sed
effectué la q
commande uit avant d'atteindre EOF, donc il a laissé le fichier décalé au début de la zzz
ligne, donc cat
peut continuer à imprimer les lignes restantes (GNU sed n'est pas compatible POSIX dans certaines conditions, voir ci-dessous).
Et en continuant du doc:
Pour les fichiers qui ne peuvent pas être recherchés, l'état de l'offset de fichier dans la description du fichier ouvert pour ce fichier n'est pas spécifié
Dans ce cas, le comportement n'est pas spécifié. La plupart des outils standard, notamment sed
, consommeront l'entrée autant que possible. Il lit la yyy
ligne, et q
uit sans restaurer l'offset du fichier, donc rien n'est laissé pour cat
.
GNU sed
n'est pas conforme à la norme, dépend de l'implémentation stdio du système et de la version glibc:
$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa
Ici, le résultat a été obtenu à partir de Mac OSX 10.11.6, machines virtuelles Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19, qui sont exécutées sur Openstack avec backend CEPH.
Sur ces systèmes, vous pouvez utiliser l' -u
option pour obtenir le comportement standard:
(gsed -u '/y/ q'; echo aaa; cat) </tmp/test
et pour tuyau:
$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz
ce qui conduit à des performances terriblement inefficaces, car sed
doit lire un octet à la fois. Une sortie partielle de strace
:
$ strace -fe read sh -c '{ sed -u "/y/q"; echo aaa; cat; } <test'
...
[pid 5248] read(3, "", 4096) = 0
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
xxx
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
yyy
...
cat
(dans le sous-shell) peut réutiliser le descripteur de fichier dans le premier cas, car stdin est lié à un vrai fichier. Dans le second cas, stdin provient d'un tube et non d'un vrai fichier. Notez que(sed '/y/ q'; echo aaa; cat) < <(cat test)
ne s'imprime pas non pluszzz
.