¿Son inteligentes las utilidades de Linux cuando se ejecutan comandos canalizados?

23

Solo estaba ejecutando algunos comandos en una terminal y comencé a preguntarme, ¿Unix / Linux toma atajos cuando ejecuta comandos canalizados?

Por ejemplo, supongamos que tengo un archivo con un millón de líneas, de las cuales las primeras 10 contienen hello world. Si ejecuta el comando, grep "hello world" file | head¿se detiene el primer comando tan pronto como encuentra 10 líneas, o continúa buscando primero todo el archivo?

Cabra descontento
fuente
2
Es por eso que gnu grep tiene el -margumento.
Paul Tomblin
3
La terminal no tiene nada que ver con eso. Los comandos canalizados son administrados por el shell.
Keith Thompson el
@KeithThompson disculpe mi ignorancia, no soy grande en terminología, no estaba seguro de si llamarlo terminal, shell o línea de comando. Siéntase libre de sugerir modificaciones a mi pregunta :)
DisgruntledGoat

Respuestas:

30

Más o menos. El shell no tiene idea de lo que harán los comandos que está ejecutando, solo conecta la salida de uno con la entrada del otro.

Si grepencuentra más de 10 líneas que dicen "hola mundo", headtendrá las 10 líneas que desee y cierre la tubería. Esto provocará la grepmuerte con un SIGPIPE, por lo que no es necesario que continúe escaneando un archivo muy grande.

psusi
fuente
2
Entonces, supongo que, debido a las condiciones de la carrera, grep podría haber leído el 11 ° o 12 ° patrón, pero probablemente no el 100 mil.
usuario desconocido el
3
Esto depende en parte de la longitud de las líneas y el tamaño del búfer de tubería, pero la respuesta corta es que grep leerá una cantidad razonablemente limitada de datos adicionales antes de matarlos.
dmckee
1
@userunknown, exactamente.
psusi
Genial, no sabía que sucedió. Pensé grepque seguiría enviando la salida a un vacío, similar a/dev/null
Izkata
15

Cuando un programa intenta escribir en una tubería y no hay una lectura de proceso de esa tubería, el programa escritor recibe una señal SIGPIPE . La acción predeterminada cuando un programa recibe SIGPIPE es terminar el programa. Un programa puede elegir ignorar la señal SIGPIPE, en cuyo caso la escritura devuelve un error ( EPIPE).

En su ejemplo, aquí hay una línea de tiempo de lo que sucede:

  • Los comandos grepy se headinician en paralelo.
  • grep lee alguna entrada, comienza a procesarla.
  • En algún momento, grepproduce un primer fragmento de salida.
  • head lee ese primer fragmento y lo escribe.
  • Suponiendo que haya suficientes líneas después de las primeras 10 coincidencias (de lo contrario, greppodría terminar primero), finalmente headhabrá impreso el número deseado de líneas. En este punto, headsalidas.
  • Dependiendo de la velocidad relativa de los procesos grepy head, es grepposible que haya acumulado algunos datos y aún no los haya impreso. En el momento en que headsale, greppuede estar leyendo entradas o haciendo un procesamiento interno, en cuyo caso continuará haciéndolo.
  • Pronto grepescribiremos los datos que se procesan. En ese punto, recibirá un SIGPIPE y morirá.

Es probable que grepprocese un poco más de entrada de lo estrictamente necesario, pero generalmente solo unos pocos kilobytes:

  • headnormalmente se lee en fragmentos de unos pocos kilobytes (porque eso es más eficiente que emitir una readllamada al sistema para cada byte; este comportamiento se llama almacenamiento en búfer), por lo que el resto del último fragmento después de que se descarta la última línea deseada.
  • Puede haber algunos datos en tránsito, ya que las tuberías tienen un búfer asociado administrado por el núcleo (a menudo 512 bytes). Estos datos serán descartados.
  • greppuede haber acumulado algunos datos que están listos para convertirse en un fragmento de salida (almacenamiento en búfer de nuevo). Recibirá SIGPIPE cuando intente vaciar su búfer de salida.

En general, el sistema está diseñado con precisión para que las utilidades de filtrado se comporten de manera eficiente de manera natural. Los programas que necesitan continuar cuando su canal de salida se extingue deben dar el paso de ignorar la señal SIGPIPE.

Gilles 'SO- deja de ser malvado'
fuente
3

En cierto modo, la canalización funciona así: primero ejecuta el primer comando y luego el segundo comando en su caso.

Es decir, seamos A|Bel comando dado. Entonces es incierto si Ao Bcomienza primero. Pueden comenzar exactamente al mismo tiempo si hay varias CPU. Una tubería puede contener una cantidad de datos indefinida pero finita.

Si B intenta leer desde la tubería, pero no hay datos disponibles, Besperará hasta que lleguen los datos. Si Bestaba leyendo desde un disco, Bpodría tener el mismo problema y necesitar esperar hasta que termine la lectura de un disco. Una analogía más cercana sería leer desde un teclado. Allí, Btendría que esperar a que un usuario escriba. Pero en todos estos casos, B ha comenzado una operación de "lectura" y debe esperar hasta que termine. Pero si Bes un comando de tal manera que solo necesita una salida parcial, SIGPIPE matará Adespués de cierto punto donde Bse alcanza el nivel de entrada de s.A

Si Aintenta escribir en la tubería y la tubería está llena, Adebe esperar a que quede espacio libre en la tubería. Apodría tener el mismo problema si estuviera escribiendo en una terminal. Una terminal tiene control de flujo y puede moderar el ritmo de los datos. En cualquier caso, a A, ha comenzado una operación de "escritura" y esperará hasta que finalice la operación de escritura.

Ay Bse comportan como coprocesos, aunque no todos los coprocesos se comunicarán con una tubería. Ninguno de los dos tiene el control total del otro.

harish.venkat
fuente
1
La pregunta es: "¿qué haría A cuando B cierra su lado de la tubería?"
enzotib
2
¿No sería eso una 'tubería rota'?
Patkos Csaba
1
Si un programa intenta leer / escribir desde / hacia una tubería cerrada (por ejemplo, headsale), se produce una señal SIGPIPE en el programa y el comportamiento predeterminado es salir.
Lekensteyn
¿Cómo responde esto exactamente a la pregunta? Parece que la respuesta de psusi es más corta y más precisa .
jw013
1

grepno tiene control directo de la tubería (solo está recibiendo datos), y la tubería no tiene control directo de grep(solo está enviando datos) ...

Lo que grep, o cualquier otro programa hace, depende completamente de la lógica interna de ese programa. Si le indica a greptravés de las opciones de la línea de comandos que haga una salida temprana cuando se encuentre , entonces lo hará, de lo contrario, continuará hasta el final del archivo buscando el patrón ...

La Terminal también está bastante desconectada del funcionamiento interno de greplas shellacciones de tuberías ... La Terminal es básicamente una plataforma de lanzamiento y una pantalla de salida ...

Peter.O
fuente