¿Cómo se realiza la modificación in situ de un archivo?

10

¿Qué significa la modificación "in situ" de un archivo, por ejemplo, vía sed -io perl -isignifica?
Mi pregunta es sobre cómo se realiza esta modificación in situ. ¿Se copia el archivo, la modificación se realiza en la copia y luego se reemplaza el original? ¿O se está modificando de alguna manera el archivo original?

Jim
fuente
Eche un vistazo a backreference.org/2011/01/29/in-place-editing-of-files para obtener una explicación detallada de este tema.
scy
Para el caso, ¿cómo se hace con exo vi?
Comodín
@Wildcard: cada uno de ellos tiene un sistema completo en su lugar. exmantiene un archivo de correo (como, dead.mailo algo en usted, y otro en algún lugar cerca de su cola de correo, por lo general) . verifique las especificaciones: cada una de ellas tiene un estado definido a grandes longitudes ... extiene su propio formato binario en la mayoría de los casos (mire su -rescuearchivo) y esto se usa para precerrar por separado los archivos de búfer temporales (posiblemente hasta seis) . Entonces, ¿estos bloques de entrada de copia para editar buffers y sincronizar escrituras en compensaciones por cambios :!written?
mikeserv

Respuestas:

18

sed crea un archivo temporal, escribe el resultado en ese archivo y luego cambia el nombre del archivo temporal sobre la parte superior del original.

Puedes ver lo que sucede usando strace:

$ strace -e trace=file sed -i -e '' a
execve("/usr/bin/sed", ["sed", "-i", "-e", "", "a"], [/* 34 vars */]) = 0
<...trimmed...>
open("a", O_RDONLY)                     = 3
open("./sedxvhRY8", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("./sedxvhRY8", "a")              = 0
+++ exited with 0 +++

Esto registra todas las operaciones de archivo sed: crea un nuevo archivo (de forma segura con O_CREAT|O_EXCL), escribe los datos en él y luego lo mueve de nuevo sobre la parte superior de mi archivo original a.

sed -iacepta un sufijo para usar como copia de seguridad y, en ese caso, primero quita el original (en lugar de renombrarlo en la parte superior). Ese argumento es obligatorio en la mayoría de los BSD sed. En este caso, hay un breve momento en el que no hay ningún archivo con el nombre correcto en el directorio.

perl en versiones recientes abre el archivo de entrada, luego lo elimina y crea un nuevo archivo con el mismo nombre:

open("a", O_RDONLY)               = 3
unlink("a")                       = 0
open("a", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4

Cuando elimina ( unlink) un archivo que ya tiene abierto, conserva el acceso al mismo mientras mantenga el control, para que pueda seguir leyendo los datos del archivo eliminado. De esta manera, perlescribe directamente en el archivo de salida, en lugar de hacerlo en un archivo temporal: no se crea ningún archivo adicional, pero si lee el archivo durante el proceso, obtendrá contenido parcial, a diferencia seddel enfoque. También hay un breve momento en el que no hay un archivo con el nombre correcto, que se encuentra al comienzo del proceso en lugar de al final (como en sed -i .bak).


Ambos sedy lo perlharán:

  • Reemplace un enlace simbólico con un archivo ordinario.
  • Romper enlaces duros.
  • Preservar la propiedad del grupo si es posible.
  • Cree el archivo con su grupo predeterminado (o el grupo del directorio principal si ese directorio tiene el setgidbit) si era propiedad de un grupo en el que no está y no es root.
  • Preserve la propiedad del archivo si es root.
  • Preservar los permisos básicos.
  • Conservar setuidy setgrpbits, si el grupo resultante es el mismo que el grupo en el que comenzó.
  • Preserve la parte pegajosa.
  • No preservar xattrs.

sed será:

  • Preserve las ACL (en Linux; no sé sobre otros) .

perl será:

  • No preservar las ACL.

Lo anterior es cierto en Linux con GNU sedy Mac OS X con su (derivado de FreeBSD) sed.

Michael Homer
fuente
3

Además de la respuesta de @ Homer, de perldoc perlrun:

especifica que los archivos procesados ​​por la construcción "<>" deben editarse in situ. Para ello, renombra el archivo de entrada, abre el archivo de salida con el nombre original y selecciona ese archivo de salida como predeterminado para las declaraciones print (). La extensión, si se proporciona, se usa para modificar el nombre del archivo antiguo para hacer una copia de seguridad, siguiendo estas reglas:

Si no se proporciona ninguna extensión, no se realiza una copia de seguridad y se sobrescribe el archivo actual.

Si la extensión no contiene un *, se agrega al final del nombre de archivo actual como sufijo. Si la extensión contiene uno o más * caracteres, cada * se reemplaza con el nombre de archivo actual.

Y recuerde que no se conserva ningún enlace suave o enlace duro:

Tenga en cuenta que debido a que -i renombra o elimina el archivo original antes de crear un nuevo archivo con el mismo nombre, no se conservarán los enlaces suaves y duros de estilo UNIX.

Finalmente, el modificador -i no impide la ejecución cuando no se proporcionan archivos en la línea de comando. En este caso, no se realiza ninguna copia de seguridad (el archivo original no puede, por supuesto, determinarse) y el procesamiento continúa de STDIN a STDOUT como podría esperarse.

Esto también explica por qué debe utilizar -icon la -popción, o utilizar una explícita printdeclaración si desea editar in-situ con perl:

# Opps, file will be truncated, becomes empty
$ perl -i.bak -ne 's/123/qwe/' file

# Right way
$ perl -i.bak -ne 's/123/qwe/;print' file

# Or
$ perl -i.bak -pe 's/123/qwe/' file
Cuonglm
fuente