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 la INPUT FILES
sección en este enlace ).
Cita del documento:
Cuando una utilidad estándar lee un archivo de entrada que se puede buscar y finaliza sin un error antes de que llegue al final del archivo, la utilidad se asegurará de que el desplazamiento del archivo en la descripción del archivo abierto esté colocado correctamente justo después del último byte procesado por la utilidad.
Entonces en:
(sed '/y/ q'; echo aaa; cat) < test
sed
realizó el q
comando uit antes de llegar a EOF, por lo que dejó el desplazamiento del archivo al comienzo de la zzz
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:
Para los archivos que no son buscables, el estado del desplazamiento del archivo en la descripción del archivo abierto para ese archivo no está especificado
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 la yyy
línea y q
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:
$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa
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:
(gsed -u '/y/ q'; echo aaa; cat) </tmp/test
y para pipa:
$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz
lo que conduce a un rendimiento terriblemente ineficiente, porque sed
tiene que leer un byte a la vez. Una salida parcial 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
(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
.