Creé un archivo de prueba llamado 'prueba' que contiene lo siguiente:
xxx
yyy
zzz
Ejecuté el comando:
(sed '/y/ q'; echo aaa; cat) < test
y obtuve:
xxx
yyy
aaa
zzz
Entonces corrí:
cat test | (sed '/y/ q'; echo aaa; cat)
y consiguió:
xxx
yyy
aaa
Pregunta
sed
lee e imprime hasta que encuentra una línea con 'y', luego se detiene. En el primer caso, pero no en el segundo, el gato lee e imprime el resto.
¿Alguien puede explicar qué fenómeno está detrás de esta diferencia de comportamiento?
También noté que funciona de esta manera en Ubuntu 16.04 y Centos 6, pero en Centos 7 ninguno de los comandos imprime 'zzz'.
cat
(en el sub shell) puede reutilizar el descriptor de archivo en el primer caso, porque stdin está vinculado a un archivo real. En el segundo caso, stdin es de una tubería y no de un archivo real. Tenga en cuenta que(sed '/y/ q'; echo aaa; cat) < <(cat test)
tampoco se imprimezzz
.(head -n1; head -n1) < test
ycat test | (head -n1; head -n1)
Respuestas:
Cuando el archivo de entrada se puede buscar (como leer desde un archivo normal) o no se puede buscar (como leer desde una tubería),
sed
(y otras utilidades estándar) se comportarán de manera diferente (lea laINPUT FILES
sección en este enlace ).Cita del documento:
Entonces en:
sed
realizó elq
comando uit antes de llegar a EOF, por lo que dejó el desplazamiento del archivo al comienzo de lazzz
línea, por lo quecat
puede continuar imprimiendo las líneas (GNU sed no es compatible con POSIX en alguna condición, consulte a continuación).Y continuando desde el documento:
En este caso, el comportamiento no está especificado. La mayoría de las herramientas estándar, include
sed
, consumirán la entrada tanto como sea posible. Leyó pasar layyy
línea yq
uit sin restaurar el desplazamiento del archivo, por lo que no queda nada paracat
.GNU
sed
no cumple con el estándar, depende de la implementación estándar del sistema y la versión de glibc:Aquí, el resultado se obtuvo de Mac OSX 10.11.6, máquinas virtuales Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19, que se ejecutan en Openstack con backend CEPH.
En esos sistemas, puede usar la
-u
opción para lograr el comportamiento estándar:y para pipa:
lo que conduce a un rendimiento terriblemente ineficiente, porque
sed
tiene que leer un byte a la vez. Una salida parcial destrace
:fuente
sed
, eso depende de la implementación estándar del sistema. En los sistemas GNU (con GNU libc), GNUsed
será compatibleexit()
y buscará archivos administrados por stdio.sed
no es compatible, mi portátil manjaro sí, todos tienen la mismased
versión 4.2.2strace -f sh -c '{ sed "/y/q"; echo aaa; cat; } <test'
demuestro que nolseek()
se realizó nada , mientras que en mi manjarolseek()
se llamó antesexit_group()
.main() { char buf[999]; gets(buf); }'
programa.