J'ai créé un fichier de test nommé 'test' qui contient les éléments suivants:
xxx
yyy
zzz
J'ai exécuté la commande:
(sed '/y/ q'; echo aaa; cat) < test
et j'ai eu:
xxx
yyy
aaa
zzz
Puis j'ai couru:
cat test | (sed '/y/ q'; echo aaa; cat)
et a obtenu:
xxx
yyy
aaa
Question
sed
lit et imprime jusqu'à ce qu'il rencontre une ligne avec «y», puis s'arrête. Dans le premier cas, mais pas dans le second, cat lit et imprime le reste.
Quelqu'un peut-il expliquer quel phénomène se cache derrière cette différence de comportement?
J'ai également remarqué que cela fonctionne de cette façon dans Ubuntu 16.04 et Centos 6, mais dans Centos 7, aucune des commandes n'imprime «zzz».
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
.(head -n1; head -n1) < test
etcat test | (head -n1; head -n1)
Réponses:
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:
Donc dans:
sed
effectué laq
commande uit avant d'atteindre EOF, donc il a laissé le fichier décalé au début de lazzz
ligne, donccat
peut continuer à imprimer les lignes restantes (GNU sed n'est pas compatible POSIX dans certaines conditions, voir ci-dessous).Et en continuant du doc:
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 layyy
ligne, etq
uit sans restaurer l'offset du fichier, donc rien n'est laissé pourcat
.GNU
sed
n'est pas conforme à la norme, dépend de l'implémentation stdio du système et de la version glibc: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:et pour tuyau:
ce qui conduit à des performances terriblement inefficaces, car
sed
doit lire un octet à la fois. Une sortie partielle destrace
:la source
sed
, cela dépend de l'implémentation stdio du système. Sur les systèmes GNU (avec la libc GNU), GNUsed
sera conforme, tout commeexit()
les fichiers gérés par stdio.sed
n'est pas conforme, mon portable manjaro en a, tous ont la mêmesed
version 4.2.2strace -f sh -c '{ sed "/y/q"; echo aaa; cat; } <test'
montrez qu'aucune n'alseek()
été effectuée, alors que dans mon manjaro, une alseek()
été appelée avantexit_group()
.main() { char buf[999]; gets(buf); }'
programme.