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 EOF
y 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?
cat
almacenando en búfer hasta que se cierra la entrada estándar.tr
ysed
hacer líneas de procesocat
antes 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|tr
ycat|tr|sed
). Pero hay una excepción: GNUcat
nunca amortigua su salida. No se usastdio
o cambia lastdio
política de almacenamiento en búfer predeterminada .Puedo estar bastante seguro de que estás usando GNU
cat
y no algún otro Unixcat
porque los demás no se comportarían de esta manera. Unix tradicionalcat
tiene una-u
opción para solicitar una salida sin búfer. GNUcat
ignora la-u
opción porque su salida siempre está sin búfer.Entonces, siempre que tenga una tubería con un
cat
a la izquierda, en el sistema GNU, el paso de datos a través de la tubería no se retrasará. Elcat
ni 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|sed
ejemplo,tr
sigue recibiendo datoscat
tan pronto como presiona Enter, perotr
sigue lastdio
polí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.sed
también sigue lastdio
polí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: sised
bloqueaba su salida, tendría que escribir el doble (para llenartr
el búfer de salida ysed
la salida de buffer).GNU
sed
tiene la-u
opción, por lo que si invierte el orden y lo usacat|sed -u|tr
, verá que la salida aparece instantáneamente nuevamente. (Lased -u
opció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
stdbuf
que le permite alterar el modo de almacenamiento en búfer de cualquier comando que use losstdio
valores predeterminados. Es un poco frágil ya que utilizaLD_PRELOAD
para lograr algo que la biblioteca C no fue diseñada para soportar, pero en este caso parece funcionar:fuente
tee
ydd
tambié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 destdbuf
tuberí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 | sed
en los elementos de depuración anteriores:Entonces evidentemente
tr
amortiguadores. ¡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 entr
osed
có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
stdbuf
que también podría ser útil. unix.stackexchange.com/questions/182537/…