¿Cómo evito que sed -i destruya enlaces simbólicos?

21

¿Por qué sed -iejecutado en enlace simbólico destruye ese enlace y lo reemplaza con el archivo de destino? ¿Cómo evitar esto?

p.ej.

$ ls -l pet*
-rw-rw-r-- 1 madneon madneon 4 mar 23 16:46 pet
lrwxrwxrwx 1 madneon madneon 6 mar 23 16:48 pet_link -> pet

$ sed -i 's/cat/dog/' pet_link

$ ls -l pet*
-rw-rw-r-- 1 madneon madneon 4 mar 23 16:48 pet
-rw-rw-r-- 1 madneon madneon 4 mar 23 16:49 pet_link

¿Y por qué no se considera un error?

madneon
fuente

Respuestas:

25

El -i/--in-place bandera edita un archivo en su lugar. De manera predeterminada, sedlee el archivo dado, lo procesa en un archivo temporal, luego copia el archivo temporal sobre el original, sin verificar si el original era un enlace simbólico.

GNU sedtiene una --follow-symlinksbandera, lo que hace que se comporte como quieras:

$ echo "cat" > pet
$ ln --symbolic pet pet_link
$ sed --in-place --follow-symlinks 's/cat/dog/' pet_link
$ cat pet
dog
Anko
fuente
66
No edita un archivo en su lugar, pero edita una copia temporal del archivo en el directorio actual y luego mueve esa copia temporal sobre el original.
mikeserv
@mikeserv Me salteé los detalles de implementación porque la pregunta era sobre la interfaz. Es bueno saberlo, ¡gracias!
Anko
1

No es un error, esto es por diseño ya que sedes un S TREAM ED itor, no un editor de archivos. Básicamente hace una copia y reemplaza el archivo original con la copia. BashFAQ

Alternativamente, puede usar el excomando que tiene una sintaxis similar para la sustitución, por ejemplo

ex +%s/cat/dog/ge -scwq pet_link

o múltiples archivos:

ex "+bufdo! %s/cat/dog/ge" -scxa **/pet_link*

No destruirá los enlaces simbólicos.

Relacionado: ¿Cómo evito que sed destruya enlaces duros?

kenorb
fuente
0

Me parece que esto también funciona bien (preservando los enlaces simbólicos y duros):

sed 's/cat/dog/' pet_link > pet_link.tmp
cat pet_link.tmp > pet_link
rm pet_link.tmp
dashohoxha
fuente
0

Hay una solución que a veces usamos para escribir en el mismo archivo que se lee. Aquí hay un extracto de la página del manual:

   sponge reads standard input and writes it out to the specified file.
   Unlike a shell redirect, sponge soaks up all its input before opening
   the output file. This allows constructing pipelines that read from and
   write to the same file.

   It also creates the output file atomically by renaming a temp file into
   place, and preserves the permissions of the output file if it already
   exists. If the output file is a special file or symlink, the data will
   be written to it.

Aquí hay un fragmento que muestra que puede preservar enlaces simbólicos, aunque generalmente lo uso para preservar inodes:

# Utility functions: print-as-echo, print-line-with-visual-space.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }

rm -f pet pet_link
echo "cat" > pet
pl " Input data file $FILE:"
head -v pet

pl " Results, before sed:"
ln --symbolic pet pet_link
ls -ligG pet pet_link
# sed --in-place --follow-symlinks 's/cat/dog/' pet_link
pe
pe " Results, after sed:"
sed 's/cat/dog/' pet_link | sponge pet_link
head -v pet
ls -ligG pet pet_link

que produce:

-----
 Input data file data1:
==> pet <==
cat

-----
 Results, before sed:
1571283 -rw-r--r-- 1 4 Nov 26 23:03 pet
1571286 lrwxrwxrwx 1 3 Nov 26 23:03 pet_link -> pet

 Results, after sed:
==> pet <==
cat
1571283 -rw-r--r-- 1 4 Nov 26 23:03 pet
1571286 lrwxrwxrwx 1 3 Nov 26 23:03 pet_link -> pet

En un sistema como:

OS, ker|rel, machine: Linux, 3.16.0-4-amd64, x86_64
Distribution        : Debian 8.9 (jessie) 
bash GNU bash 4.3.30

El código de la esponja está disponible en un paquete moreutils , algunos detalles:

sponge  soak up standard input and write to a file (man)
Path    : /usr/bin/sponge
Package : moreutils
Home    : http://kitenet.net/~joey/code/moreutils/
Version : 0.52
Type    : ELF 64-bit LSB executable, x86-64, version 1 (SYS ...)

En nuestra tienda, escribimos una versión que escribe en un archivo temporal para el caso de archivos muy grandes.

El paquete está disponible en Debian, Fedora, macOS (a través de brew), etc. ... saludos,

drl
fuente