No entiendo cómo fluyen los datos en la tubería y espero que alguien pueda aclarar lo que está sucediendo allí.
Pensé que una tubería de comandos procesa archivos (texto, matrices de cadenas) en línea por línea. (Si cada comando funciona línea por línea). Cada línea de texto pasa a través de la tubería, los comandos no esperan a que el anterior termine de procesar toda la entrada.
Pero parece que no es así.
Aquí hay un ejemplo de prueba. Hay algunas líneas de texto. Las mayúsculas y repito cada línea dos veces. Lo hago con cat text | tr '[:lower:]' '[:upper:]' | sed 'p'.
Para seguir el proceso podemos ejecutarlo "interactivamente": omita el nombre de archivo de entrada cat. Cada parte de la tubería corre línea por línea:
$ cat | tr '[:lower:]' '[:upper:]'
alkjsd
ALKJSD
sdkj
SDKJ
$ cat | sed 'p'
line1
line1
line1
line 2
line 2
line 2
Pero la tubería completa espera a que termine la entrada con EOFy solo luego imprime el resultado:
$ cat | tr '[:lower:]' '[:upper:]' | sed 'p'
I am writing...
keep writing...
now ctrl-D
I AM WRITING...
I AM WRITING...
KEEP WRITING...
KEEP WRITING...
NOW CTRL-D
NOW CTRL-D
¿Se supone que es así? ¿Por qué no es línea por línea?

catalmacenando en búfer hasta que se cierra la entrada estándar.trysedhacer líneas de procesocatantes de que cierre stdinRespuestas:
Existe una regla general de almacenamiento en búfer seguida de la biblioteca de E / S estándar C (
stdio) que utilizan la mayoría de los programas Unix. Si la salida va a un terminal, se vacía al final de cada línea; de lo contrario, se vacía solo cuando el búfer (8K en mi sistema Linux / amd64; podría ser diferente en el suyo) está lleno.Si todos sus utilidades estaban siguiendo la regla general, que se vería retrasada de salida en todos sus ejemplos (
cat|sed,cat|trycat|tr|sed). Pero hay una excepción: GNUcatnunca amortigua su salida. No se usastdioo cambia lastdiopolítica de almacenamiento en búfer predeterminada .Puedo estar bastante seguro de que estás usando GNU
caty no algún otro Unixcatporque los demás no se comportarían de esta manera. Unix tradicionalcattiene una-uopción para solicitar una salida sin búfer. GNUcatignora la-uopción porque su salida siempre está sin búfer.Entonces, siempre que tenga una tubería con un
cata la izquierda, en el sistema GNU, el paso de datos a través de la tubería no se retrasará. Elcatni siquiera se va línea por línea - su terminal está haciendo eso. Mientras escribe la entrada para cat, su terminal está en modo "canónico", basado en líneas, con teclas de edición como retroceso y ctrl-U que le ofrecen la oportunidad de editar la línea que ha escrito antes de enviarla Enter.En el
cat|tr|sedejemplo,trsigue recibiendo datoscattan pronto como presiona Enter, perotrsigue lastdiopolítica predeterminada: su salida se dirige a una tubería, por lo que no se vacía después de cada línea. Escribe en la segunda tubería cuando el búfer está lleno o cuando se recibe un EOF, lo que ocurra primero.sedtambién sigue lastdiopolítica predeterminada, pero su salida se dirige a un terminal, por lo que escribirá cada línea tan pronto como haya terminado. Esto tiene un efecto sobre cuánto debe escribir antes de que algo aparezca en el otro extremo de la tubería: sisedbloqueaba su salida, tendría que escribir el doble (para llenartrel búfer de salida ysedla salida de buffer).GNU
sedtiene la-uopción, por lo que si invierte el orden y lo usacat|sed -u|tr, verá que la salida aparece instantáneamente nuevamente. (Lased -uopción puede estar disponible en otros lugares, pero no creo que sea una tradición antigua de Unixcat -u) Hasta donde puedo decir, no hay una opción equivalente paratr.Hay una utilidad llamada
stdbufque le permite alterar el modo de almacenamiento en búfer de cualquier comando que use losstdiovalores predeterminados. Es un poco frágil ya que utilizaLD_PRELOADpara lograr algo que la biblioteca C no fue diseñada para soportar, pero en este caso parece funcionar:fuente
teeyddtambién suelen jugar según sus propias reglas. Cuando se combinan de manera imaginativa, las tres herramientas pueden negar de forma bastante portátil cualquier necesidad destdbuftuberías en segundo plano.Esto en realidad me llevó un poco de pensamiento para entender y aún más para responder. Gran pregunta (la votaré a continuación).
Olvidó intentar
tr | seden los elementos de depuración anteriores:Entonces evidentemente
tramortiguadores. ¡Aprenda algo nuevo cada día!EDITAR :
Mientras pienso en esto, hemos aislado la causa, pero no hemos proporcionado una explicación. Si
cat | tr, escribe de inmediato, sicat | sed, escribe de inmediato, pero sitr | sed, se espera paraEOF. Yo sugeriría que la respuesta podría ser enterrado entrosedcódigo fuente entonces, y no ser un problema de la tubería.EDITAR :
Veo que Wumpus proporcionó la explicación mientras escribía la última edición. ¡Gracias!
fuente
stdbufque también podría ser útil. unix.stackexchange.com/questions/182537/…