sed -iがシンボリックリンクを破壊しないようにするにはどうすればよいですか?


21

sed -iシンボリックリンクで実行すると、なぜそのリンクが破壊され、リンク先ファイルに置き換えられるのですか?これを避ける方法は?

例えば。

$ 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

そして、なぜそれがバグと見なされないのですか?

回答:


25

-i/ --in-placeフラグは、場所にファイルを編集します。デフォルトでsedは、指定されたファイルを読み取り、一時ファイルに出力する処理を行ってから、元のファイルがシンボリックリンクかどうかを確認せずに、元のファイルに一時ファイルをコピーします。

GNU sedには--follow-symlinksフラグがあり、必要に応じて動作します。

$ echo "cat" > pet
$ ln --symbolic pet pet_link
$ sed --in-place --follow-symlinks 's/cat/dog/' pet_link
$ cat pet
dog

6
所定の場所でファイルを編集するのではなく、現在のディレクトリ内のファイルの一時コピーを編集してから、その一時コピーを元のコピーの上に移動します。
mikeserv

@mikeserv質問がインターフェースに関するものだったため、実装の詳細をスキップしました。知っておくと良いが、ありがとう!
アンコ

1

これはバグではありません。これsedは、S tream ED itorであり、ファイルエディタではないため、設計によるものです。基本的にコピーを作成し、元のファイルをコピーで置き換えます。BashFAQ

あるいは、ex代わりに同様の構文を持つコマンドを代わりに使用できます。例えば

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

または複数のファイル:

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

シンボリックリンクは破棄されません。

関連:sedがハードインクを破壊しないようにするにはどうすればよいですか?


0

私はこれもうまくいくことがわかります(シンボリックリンクとハードリンクの両方を保持します):

sed 's/cat/dog/' pet_link > pet_link.tmp
cat pet_link.tmp > pet_link
rm pet_link.tmp

0

読み取り元と同じファイルに書き込むために時々使用する解決策があります。以下はmanページからの抜粋です。

   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.

これはシンボリックリンクを保持できることを示すスニペットですが、通常はiノードを保持するために使用します。

# 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

生成するもの:

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

次のようなシステムで:

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

スポンジコードは、moreutilsパッケージで入手できます-詳細:

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

当店では、非常に大きなファイルの場合に備えて一時ファイルに書き込むバージョンを作成しました。

パッケージはDebian、Fedora、macOS(brew経由)などで利用可能です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.