Bagaimana cara mencegah sed-i dari menghancurkan symlink?

21

Mengapa sed -idieksekusi pada symlink menghancurkan tautan itu dan menggantinya dengan file tujuan? Bagaimana cara menghindarinya?

misalnya.

$ 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

Dan mengapa itu tidak dianggap sebagai bug?

Madneon
sumber

Jawaban:

25

The -i/ --in-placebendera mengedit file di tempat. Secara default, sedmembaca file yang diberikan, memprosesnya menghasilkan file sementara, lalu menyalin file sementara atas yang asli, tanpa memeriksa apakah yang asli adalah symlink.

GNU sedmemiliki --follow-symlinksbendera, yang membuatnya berperilaku seperti yang Anda inginkan:

$ echo "cat" > pet
$ ln --symbolic pet pet_link
$ sed --in-place --follow-symlinks 's/cat/dog/' pet_link
$ cat pet
dog
Anko
sumber
6
Itu tidak mengedit file di tempat, tetapi mengedit salinan temp file di direktori saat ini kemudian memindahkan salinan temp ke yang asli.
mikeserv
@ mikeserv Saya melewatkan detail implementasi karena pertanyaannya adalah tentang antarmuka. Senang tahu, terima kasih!
Anko
1

Ini bukan bug, ini adalah dengan desain karena sedmerupakan S tream ED itor, bukan file editor. Itu pada dasarnya membuat salinan dan mengganti file asli dengan salinan. BashFAQ

Atau Anda dapat menggunakan experintah sebagai gantinya yang memiliki sintaksis yang sama untuk substitusi, misalnya

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

atau beberapa file:

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

Itu tidak akan menghancurkan tautan simbolik.

Terkait: Bagaimana cara mencegah sed dari menghancurkan hardinks?

kenorb
sumber
0

Saya menemukan bahwa ini juga berfungsi dengan baik (menjaga hubungan simbolis dan keras):

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

Ada solusi yang terkadang kita gunakan untuk menulis ke file yang sama dengan yang dibaca. Berikut adalah kutipan dari halaman 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.

Berikut ini cuplikan yang menunjukkan bahwa ia dapat mempertahankan tautan simbolik, meskipun saya biasanya menggunakannya untuk menyimpan inode:

# 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

yang menghasilkan:

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

Pada sistem seperti:

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

Kode spons tersedia dalam paket moreutils - beberapa detail:

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

Di toko kami, kami menulis versi yang menulis ke file sementara untuk kasus file yang sangat besar.

Paket ini tersedia di Debian, Fedora, macOS (via minuman), dll. ... tepuk tangan,

drl
sumber