ファイルのインプレース変更はどのように行われますか?


10

ファイルの「インプレース」変更とは、たとえば、sed -iまたはそれをperl -i意味しますか?
私の質問は、このインプレース修正がどのように行われるかについてです。ファイルはコピーされますか?変更はコピーで行われ、元のファイルを置き換えますか?または、元のファイルが何らかの方法で変更されていますか?


このトピックの詳細な説明については、backreference.org / 2011/01/29 / in-place-editing- of- filesご覧ください。
scy 14

それについて、それはexor でどのように行われviますか?
ワイルドカード2016

@ワイルドカード-それらのそれぞれは、適切なシステム全体を持っています。exメールファイルを管理しますdead.mail通常、または〜you 内の何か、通常はメールスプーラに近い別の場所)。仕様を確認してください-それぞれの状態は非常exに長く定義されています... ほとんどの場合-rescueファイルを見てください)独自のバイナリ形式であり、これは個別の一時バッファーファイル(おそらく6つまで)を事前ゼロ化するために使用されます。したがって、これらの入力のブロックを編集バッファーにコピーし、変更ごとにオフセットにオフセットを同期します:!writtenか?
mikeserv

回答:


18

sed 一時ファイルを作成し、そのファイルに出力を書き込んでから、一時ファイルの名前を元のファイルの上に変更します。

何が起こるかを見ることができます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 +++

これsedにより、すべてのファイル操作のログが記録されます。新しいファイルが(安全にO_CREAT|O_EXCL)作成され、そこにデータが書き込まれ、元のファイルの上部に移動されますa

sed -iバックアップに使用するサフィックスを受け入れます。その場合、元のファイルを最初に移動します(名前を変更するのではなく)。その引数は、ほとんどのBSDで必須sedです。この場合、ディレクトリに正しい名前のファイルがまったくない場合があります。

perl 最近のバージョンでは、入力ファイルを開いてから削除し、同じ名前の新しいファイルを作成します。

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

unlinkすでに開いているファイルを削除()すると、ハンドルを保持している間はそのファイルへのアクセスが保持されるため、削除されたファイルからデータを読み取ることができます。この方法でperlは、一時ファイルではなく出力ファイルに直接書き込みます。追加のファイルは作成されませんが、プロセス中にファイルを読み取ると、sedのアプローチとは異なり、部分的なコンテンツが取得されます。また、正しい名前のファイルがない場合もあります。これは、プロセスの最後ではなく、最初にあります(などsed -i .bak)。


両方sedperl

  • シンボリックリンクを通常のファイルに置き換えます。
  • ハードリンクを解除します。
  • 可能であれば、グループの所有権を保持します。
  • デフォルトのグループ(または、そのディレクトリにsetgidビットがある場合は親ディレクトリのグループ)を使用してファイルを作成します。そのファイルが、自分が属しておらず、ルートではないグループによって所有されている場合です。
  • rootの場合、ファイルの所有権を保持します。
  • 基本的な権限を保持します。
  • 結果のグループが開始時のグループと同じ場合は、保持setuidしてsetgrpビットを保持します。
  • スティッキービットを保持します。
  • xattrsを保持しません

sed 意志:

  • ACLを保持します(Linuxの場合、他のユーザーについてはわかりません)

perl 意志:

  • ACLを保持しません

上記は、GNU sedを搭載したLinux および(FreeBSDから派生した)を搭載したMac OS Xに当てはまりますsed


3

@Homerの回答に加えて、からperldoc perlrun

"<>"構成要素によって処理されるファイルをインプレース編集することを指定します。これは、入力ファイルの名前を変更し、元の名前で出力ファイルを開き、その出力ファイルをprint()ステートメントのデフォルトとして選択することによって行われます。拡張子が指定されている場合は、次の規則に従って、古いファイルの名前を変更してバックアップコピーを作成します。

拡張子を指定しない場合、バックアップは作成されず、現在のファイルが上書きされます。

拡張子に*が含まれていない場合は、現在のファイル名の末尾にサフィックスとして追加されます。拡張子に1つ以上の*文字が含まれている場合、各*は現在のファイル名に置き換えられます。

また、ソフトリンクやハードリンクは保持されないことに注意してください。

-iは同じ名前の新しいファイルを作成する前に元のファイルの名前を変更または削除するため、UNIXスタイルのソフトリンクとハードリンクは保持されないことに注意してください。

最後に、コマンドラインでファイルが指定されていない場合、-iスイッチは実行を妨げません。この場合、バックアップは作成されず(元のファイルはもちろん決定できません)、処理はSTDINからSTDOUTに進みます。

これは、-iwith -pオプションを使用する必要がある理由、またはprintinplaceを使用して編集する場合は明示的なステートメントを使用する理由も説明します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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.