¿Cómo funciona exactamente la tubería/redirección en Linux?

¿Cómo funciona exactamente la tubería/redirección en Linux?

Tengo estos tres ejemplos de redirección stdin/stdout, solo uno de ellos funciona como debe. Me encantaría que alguien pudiera explicarme eso.

El objetivo es ordenar el contenido del archivo1 y guardar los cambios en el mismo archivo.

  1. ordenar archivo1 | tee file1 > /dev/null --------> Funciona

  2. ordenar archivo1 | tee file1 --------> Se borrará el contenido del file1

  3. ordenar archivo1 | tee file1 > file2 --------> Se borrará el contenido del file1

PD. tee copia la entrada estándar a cada ARCHIVO y también a la salida estándar.

¿Qué hace que el primer ejemplo funcione?

Respuesta1

De acuerdo con mis pruebas en Debian Wheezy, los 3 escenarios pueden llevar a ambos resultados (el archivo1 se ordena y se vuelve a escribir en sí mismo O no se ordena nada y no se escribe nada en el archivo1.

Creo que este es un comportamiento normal y se debe a la forma en que Linux trabaja con los archivos. Piense en el comando: el comando de clasificación comienza a leer el archivo1 e inmediatamente envía su salida al tee. Tee lee el resultado, lo vuelve a escribir en el archivo 1 y lo imprime en /dev/null. En caso de que la clasificación sea lo suficientemente rápida como para leer el archivo completo1, tee obtiene una salida ordenada. Pero en caso de que tee bloquee el archivo, lo borra (tee siempre borra el archivo de salida, excepto cuando se usa la opción de agregar) y eso es más o menos lo que sucede en los 3 escenarios.

Para abreviar, digamos que a veces la clasificación no es lo suficientemente rápida para leer el archivo 1. En tal caso, tee borra el archivo ANTES de que pueda leerlo.

Recomendaría el siguiente procedimiento:

cat file1 | sort > /tmp/sorting.tmp; mv /tmp/sorting.tmp file1

En caso de que quieras ver el resultado ordenado en stdout, hazlo así:

cat file1 | sort | tee /tmp/sorting.tmp; mv /tmp/sorting.tmp file1

No es una buena idea dejar que 2 comandos diferentes funcionen con 1 archivo en sistemas multiprocesador; nunca se puede estar seguro de cuál se ejecuta primero. En un sistema de un solo subproceso, el comportamiento sería diferente: secuencial.

Respuesta2

Dudo que ese comportamiento sea predecible (y seguramente no dependería de ello). El teecomando probablemente inicia un nuevo proceso para enviar su entrada al "otro" destino. El sistema operativo almacenará en búfer la salida hasta que llegue al punto en el que crea el archivo de destino y escribe su búfer temporal en el archivo. El momento exacto en que esto sucede (y sobrescribe la fuente) probablemente dependa de:

  • El tamaño del archivo y la memoria disponible para el búfer.
  • El tiempo transcurrido
  • Si la entrada desde la tubería teetermina

Esto va más allá de bash: lo que se inicia es la forma en que funcionan los programas bash. El shell simplemente interpreta los comandos que usted escribe e inicia los programas necesarios para ejecutar los comandos. El shell no tiene control sobre cómo funciona cada programa, y ​​menos aún sobre cómo interactúan esos programas. Pedirle a un programa (o un conjunto de programas) que tome datos de un archivo de entrada y escriba el resultado en el mismo archivo de entrada en la misma oración es responsabilidad del usuario.

No olvide que bash es solo el intérprete de los comandos del usuario: es solo una herramienta shellalrededor del sistema operativo para convertir las intenciones del usuario en llamadas al sistema.

Y esdocumentado, ¡también! Oeste correo, que aborda problemas similares. O estoHilo de desbordamiento de pila. Oeste hilo de Serverfault.

Tenga en cuenta que esto también puede suceder con la redirección de stdin: si toma comandos de entrada de un archivo $ myprog < commandfile:. Si myprogescribe en el archivo de comandos, no hay garantía de que commandfilese ejecuten todos los comandos.

Una analogía realmente básica sería algo como esta lista de instrucciones:

- Execute the instructions step by step
- Dip this instruction list in a bucket of black paint
- Type in the following commands:
  find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
  | grep '^[^.][^.]*\.[^.][^.]*\.[^.][^.]*\.[^.][^.]*$'

¿Me imagino que harías una copia primero? (comando tomado deGuía avanzada de secuencias de comandos Bash)

Respuesta3

¿Entonces desea que se mantenga el contenido original del archivo, mientras agrega el archivo con los cambios?

tee over writes de forma predeterminada, intente usar el indicador -a para agregar el archivo con los cambios.

Respuesta4

sort file1 | tee file1 > tmp && mv file1 original && mv tmp file1

Puede escribir el archivo en un marcador de posición, cambiar el nombre del original a una copia de seguridad y luego mover el marcador de posición al original.

información relacionada