¿Por qué redirigir la salida de un archivo a sí mismo produce un archivo en blanco?
Dicho en Bash, ¿por qué
less foo.txt > foo.txt
y
fold foo.txt > foo.txt
producir un vacío foo.txt
? Como un apéndice como less eggs.py >> eggs.py
produce dos copias del texto eggs.py
, se podría esperar que una sobrescritura produzca una copia del texto.
Tenga en cuenta que no estoy diciendo que esto sea un error, es más probable que sea un puntero a algo profundo sobre Unix.
bash
unix
unix-utils
Seewalker
fuente
fuente
Respuestas:
Cuando lo usa
>
, el archivo se abre en modo de truncamiento, por lo que su contenido se elimina antes de que el comando intente leerlo.Cuando lo usa
>>
, el archivo se abre en modo anexar para que se conserven los datos existentes. Sin embargo, todavía es bastante arriesgado usar el mismo archivo como entrada y salida en este caso. Si el archivo es lo suficientemente grande como para no ajustarse al tamaño del búfer de entrada de lectura, su tamaño puede crecer indefinidamente hasta que el sistema de archivos esté lleno (o se alcance su cuota de disco).Si desea utilizar un archivo como entrada y salida con un comando que no admite la modificación en el lugar, puede utilizar un par de soluciones:
Utilice un archivo intermediario y sobrescriba el original cuando haya terminado y solo si no se produjo ningún error al ejecutar la utilidad (esta es la forma más segura y común).
Evite el archivo intermediario a expensas de una posible pérdida parcial o completa de datos en caso de que ocurra un error o una interrupción. En este ejemplo, el contenido de
foo.txt
se pasa como entrada a una subshell (dentro de los paréntesis) antes de eliminar el archivo. El inodo anterior permanece vivo ya que la subshell lo mantiene abierto mientras lee datos. El archivo escrito por la utilidad interna (aquífold
) mientras tiene el mismo nombre (foo.txt
) apunta a un inodo diferente porque la entrada de directorio anterior se ha eliminado técnicamente, hay dos "archivos" diferentes con el mismo nombre durante el proceso. Cuando finaliza la subshell, se libera el inodo anterior y se pierden sus datos. Tenga cuidado de asegurarse de tener suficiente espacio para almacenar temporalmente tanto el archivo antiguo como el nuevo al mismo tiempo, de lo contrario perderá datos.fuente
sponge
from moreutils también puede ayudar.fold foo.txt | sponge foo.txt
- Ofold foo.txt | sponge !$
también debería hacerlo.El shell abre el archivo para que lo escriba antes de que la aplicación tenga la oportunidad de leerlo. Abrir el archivo para escribir lo trunca.
fuente
En bash, el operador de redirección de flujo se
... > foo.txt
vacíafoo.txt
antes de evaluar el operando izquierdo .Uno podría usar la sustitución de comandos e imprimir su resultado como una solución alternativa. Esta solución toma menos caracteres adicionales que en otras respuestas:
Cuidado: este comando no conserva ninguna línea nueva de seguimiento
foo.txt
. Echa un vistazo a la sección de comentarios a continuación para obtener más información.Aquí, la subshell
$(...)
se evalúa antes que el operador de redirección de flujo>
, de ahí la preservación de la información.fuente
tmp=$(cmd; printf q); printf '%s' "${tmp%q}"
. Pero se perdió otro problema con esta respuesta: dice "subshell" cuando significa "sustitución de comando". Sí, las sustituciones de comandos son generalmente subcapas, pero no al revés, y las subcapas, en general, no son de ayuda para este problema.