Comment empêcher sed -i de détruire les liens symboliques?

21

Pourquoi est sed -iexécuté sur le lien symbolique détruit ce lien et le remplace par le fichier de destination? Comment éviter cela?

par exemple.

$ 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

Et pourquoi n'est-il pas considéré comme un bug?

madneon
la source

Réponses:

25

Le drapeau -i/ --in-placemodifie un fichier en place. Par défaut, sedlit le fichier donné, le traite en sortie dans un fichier temporaire, puis copie le fichier temporaire sur l'original, sans vérifier si l'original était un lien symbolique.

GNU seda un --follow-symlinksdrapeau, ce qui le fait se comporter comme vous le souhaitez:

$ echo "cat" > pet
$ ln --symbolic pet pet_link
$ sed --in-place --follow-symlinks 's/cat/dog/' pet_link
$ cat pet
dog
Anko
la source
6
Il ne modifie pas un fichier sur place, mais modifie une copie temporaire du fichier dans le répertoire en cours, puis déplace cette copie temporaire sur l'original.
mikeserv
@mikeserv J'ai ignoré les détails de l'implémentation car la question concernait l'interface. Bon à savoir cependant, merci!
Anko
1

Ce n'est pas un bug, c'est par conception car sedc'est un éditeur S tream ED , pas un éditeur de fichiers. Il fait essentiellement une copie et remplace le fichier d'origine par la copie. BashFAQ

Alternativement, vous pouvez utiliser une excommande qui a une syntaxe de substitution similaire, par exemple

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

ou plusieurs fichiers:

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

Cela ne détruira pas les liens symboliques.

Connexes: Comment empêcher sed de détruire les hardinks?

kenorb
la source
0

Je trouve que cela fonctionne aussi bien (en préservant les liens symboliques et durs):

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

Il existe une solution que nous utilisons parfois pour écrire dans le même fichier que celui lu. Voici un extrait de la page de manuel:

   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.

Voici un extrait qui montre qu'il peut préserver les liens symboliques, bien que je l'utilise généralement pour préserver les 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

qui produit:

-----
 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

Sur un système comme:

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

Le code éponge est disponible dans un package moreutils - quelques détails:

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 ...)

Dans notre boutique, nous avons écrit une version qui écrit dans un fichier temporaire pour le cas de très gros fichiers.

Le paquet est disponible sur Debian, Fedora, macOS (via brew), etc.

drl
la source