Es bien sabido que un comando como este:
cat filename | some_sed_command >filename
borra el nombre del archivo, ya que la redirección de salida, que se ejecuta antes del comando, hace que el nombre del archivo se trunca.
Se podría resolver el problema de la siguiente manera:
cat file | some_sed_command | tee file >/dev/null
pero no estoy seguro de que esto funcione en cualquier caso: ¿qué sucede si el archivo (y el resultado del comando sed) es muy grande? ¿Cómo puede el sistema operativo evitar sobrescribir algún contenido que aún no se lee? Veo que también hay un comando de esponja que debería funcionar en cualquier caso: ¿es "más seguro" que el tee?
command-line
bash
tee
VeryHardCoder
fuente
fuente
Respuestas:
No se .
Las posibilidades
file
serán truncadas, pero no hay garantía decat file | some_sed_command | tee file >/dev/null
que no se truncaránfile
.Todo depende de qué comando se procese primero, a diferencia de lo que uno puede esperar, los comandos en una tubería no se procesan de izquierda a derecha . No hay garantía sobre qué comando se elegirá primero, por lo que uno podría pensar que se eligió al azar y nunca confiar en que el caparazón no elija al infractor.
Dado que las posibilidades de que el comando ofensivo se elija primero entre tres comandos son menores que las posibilidades de que el comando ofensivo se elija primero entre dos comandos, es menos probable que
file
se trunque, pero aún así sucederá .script.sh
:Así que nunca uses algo como eso
cat file | some_sed_command | tee file >/dev/null
. Usesponge
como lo sugirió Oli.Como alternativa, para entornos más exigentes y / o archivos relativamente pequeños, se puede usar una cadena here y una sustitución de comando para leer el archivo antes de ejecutar cualquier comando:
fuente
Para
sed
concreto, puede utilizar su-i
argumento en el lugar. Simplemente guarda de nuevo en el archivo que abrió, por ejemplo:Si desea hacer algo más robusto, suponiendo que está haciendo más que
sed
, sí, puede almacenar todo el contenidosponge
(desde elmoreutils
paquete) que "absorberá" todo el stdin antes de escribirlo en el archivo. Es comotee
pero con menos funcionalidad. Sin embargo, para un uso básico, es prácticamente un reemplazo directo:¿Es eso más seguro? Seguro. Probablemente tiene límites, por lo que si está haciendo algo colosal (y no puede editar en el lugar con sed), es posible que desee hacer sus ediciones en un segundo archivo y luego
mv
ese archivo nuevamente al nombre de archivo original. Eso debería ser atómico (por lo que todo lo que dependa de estos archivos no se romperá si necesitan acceso constante).fuente
Puede usar Vim en modo Ex:
%
seleccione todas las líneas!
Ejecutar comandox
Guardar y Salirfuente
Ah, pero
sponge
no es la única opción; no tiene que obtenermoreutils
para que esto funcione correctamente. Cualquier mecanismo funcionará siempre que satisfaga los siguientes dos requisitos:Verá, el problema bien conocido al que se refiere el OP es que el shell creará todos los archivos que son necesarios para que las tuberías funcionen incluso antes de comenzar a ejecutar los comandos en la tubería, por lo que es el shell el que realmente se trunca el archivo de salida (que desafortunadamente también es el archivo de entrada) antes de que cualquiera de los comandos haya tenido la oportunidad de comenzar a ejecutarse.
El
tee
comando no funciona, aunque cumple con el primer requisito, porque no cumple con el segundo requisito: siempre creará el archivo de salida inmediatamente después del inicio, por lo que es esencialmente tan malo como crear una tubería directamente en el archivo de salida. (En realidad, es peor, porque su uso introduce un retraso aleatorio no determinista antes de que el archivo de salida se trunca, por lo que podría pensar que funciona, mientras que de hecho no lo hace).Entonces, todo lo que necesitamos para resolver este problema es algún comando que almacenará todas sus entradas antes de producir cualquier salida, y que sea capaz de aceptar el nombre de archivo de salida como un parámetro, de modo que no tengamos que canalizar su salida a El archivo de salida. Uno de esos comandos es
shuf
. Entonces, lo siguiente logrará lo mismo quesponge
hace:La
--random-source=/dev/zero
parte engañashuf
para hacer lo suyo sin hacer ningún movimiento aleatorio, por lo que amortiguará su entrada sin alterarla.fuente