Necesito explicaciones de los usuarios avanzados para un comportamiento tan impredecible:
ps -eF | { head -n 1;grep worker; }
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
root 441 2 0 0 0 2 paź15 ? 00:00:00 [kworker/2:1H]
todo se ve bien mientras que
ls -la / | { head -n 1;grep sbin; }
muestra solo la salida de head
... Pensé stdout 2>&1y no funciona ni para mí es extraño, ¿alguna explicación o sugerencia de cómo manejarlo?

headygrepno hacer nada allí.Respuestas:
Investigué un poco usando
stracey parece deberse a la forma en que el programa en el lado izquierdo de la tubería está escribiendo en la terminal. Cuandolsse ejecuta el comando, escribe todos los datos en un solowrite(). Esto haceheadque se consuma todo el stdin.Por otro lado,
psescribe datos en lotes, por lo que solo el primerowrite()es consumido porhead, y luego existe. Las llamadas posteriores awrite()irán algrepproceso recién generado .Esto significa que no funcionaría si el proceso que está intentando
grepno se produjo en el primerowrite(), yagrepque no puede ver todos los datos (ve incluso menos que solo los datos menos la primera línea).Aquí hay un ejemplo de cómo intentar grep para pid 1 en mi sistema:
Tu
ps -eFejemplo solo funciona por casualidad.fuente
write()llamadas. Siheadtardaran en realizar suread()llamada (de modo que el búfer de la tubería tuviera todos los datos), exhibiría el mismo comportamiento en amboslsyps.Esto es causado por el almacenamiento en búfer en glibc. En el caso de
lsla salida está en un búfer interno y como tal se pasa solo ahead. Para elps -eF, la salida es más grande y, por lo tanto, una vez queheadfinaliza, lo siguientegrepobtiene las partes restantes de (pero no la totalidad) de la salidaps.Puede deshacerse de él desarmando la tubería, por ejemplo con
sed -u(no estoy seguro de que no sea una extensión GNU):fuente
Lo que sucede es que
head -n 1lee más de 1 línea. Para un rendimiento óptimo, la cabeza lee fragmentos de bytes, por lo que podría leer 1024 bytes a la vez, y luego mirar a través de esos bytes para el primer salto de línea. Dado que el salto de línea puede ocurrir en el medio de esos 1024 bytes, se pierde el resto de los datos. No se puede volver a poner en la tubería. Entonces, el siguiente proceso que se ejecuta solo obtiene los bytes 1025 y más.Su primer comando tiene éxito porque el
kworkerproceso es posterior a ese primer fragmento que seheadlee.Para que esto funcione,
headtendría que leer 1 carácter a la vez. Pero esto es extremadamente lento, por lo que no lo hace.La única forma de hacer algo como esto de manera eficiente es hacer que un solo proceso haga tanto la "cabeza" como la "grep".
Aquí hay 2 formas de hacer esto:
o
Hay muchos más ...
fuente
Si solo desea la primera o dos líneas, el siguiente tipo de truco funciona y evita los problemas de almacenamiento en búfer causados por el uso de dos comandos diferentes para leer la secuencia de salida:
El
readestá integrado en el shell y no consume un búfer completo de entrada solo para generar una línea, por lo que el usoreaddeja todo el resto de la salida para el siguiente comando.Si desea acentuar los problemas de almacenamiento en búfer que muestran sus ejemplos que usan dos comandos diferentes, agréguelos
sleepa ellos para eliminar los problemas de sincronización y permita que el comando de la izquierda genere toda su salida antes de que los comandos de la derecha intenten leer cualquiera de eso:Ahora, los dos ejemplos anteriores fallan de la misma manera:
headlee un búfer completo de la salida solo para producir una línea, y ese búfer no está disponible para lo siguientegrep.Puede ver el problema del almacenamiento en búfer aún más claramente utilizando algunos ejemplos que numeran las líneas de salida para que pueda saber qué líneas faltan:
Una forma sencilla de ver el problema del almacenamiento en búfer es utilizar
sequn generador de una lista de números. Podemos decir fácilmente qué números faltan:Mi solución truco usando el shell para leer y hacer eco de la primera línea funciona correctamente incluso con el retraso de sueño agregado:
A continuación se muestra un ejemplo completo que muestra los
headproblemas de almacenamiento en búfer, que muestra cómoheadconsume un búfer completo de la salida solo para producir sus cinco líneas cada vez. Ese búfer consumido no está disponible para el siguienteheadcomando en la secuencia:Mirando el número
1861anterior, podemos calcular el tamaño del búfer que se utilizaheadcontando laseqsalida de1a1860:Vemos que
headse almacena en búfer leyendo 8 KB completos (8 * 1024 bytes) de la salida de la tubería a la vez, incluso para producir solo unas pocas líneas de su propia salida.fuente