ファイルを内部で変更するには?

ファイルを内部で変更するには?

ファイルの「内部」修正(たとえば、または経由sed -i)とはどういうperl -i意味ですか?
私の質問は、この内部修正を実行する方法です。ファイルをコピーしてコピーを変更してからソースを置き換えますか?それとも元のファイルを適切に修正しましたか?

答え1

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出力ファイルは一時ファイルではなく直接作成されます。追加のファイルは生成されませんが、プロセス中にファイルを読み取ると、withのsed方法とは異なり、部分的な内容が得られます。また、正しい名前のファイルを持たない短い期間がありますが、これはプロセスの終わりではなく最初にあります(図を参照sed -i .bak)。


両方sedperl両方:

  • シンボリックリンクを通常のファイルに置き換えます。
  • ハードリンクを切断します。
  • 可能であれば、グループの所有権を維持してください。
  • setgidファイルがあなたが属していないグループに属し、あなたがルートでない場合、ファイルはデフォルトグループ(またはディレクトリにそのビットがある場合は親ディレクトリのグループ)を使用して作成されます。
  • ルートの場合は、ファイルの所有権を維持してください。
  • 基本的な権限を維持してください。
  • 保存setuidしてsetgrpビット、もし結果のグループは開始されたグループと同じです。
  • 粘着性のある部分を維持してください。
  • いいえxattrsが予約されました。

sedする:

  • ACLを保存します(Linuxの場合、他の場合はわかりません)

perlする:

  • いいえACLを維持してください。

上記は、GNUを使用するLinuxsedとFreeBSD派生製品を使用するMac OS Xの両方に適用されますsed

答え2

@Homerの回答に加えて、次の内容がありますperldoc perlrun

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

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

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

ソフトリンクまたはハードリンクは維持されません。

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

最後に、-iスイッチはコマンドラインにファイルが提供されていないときに実行をブロックしません。この場合、バックアップは行われず(もちろん元のファイルを確認できません)、期待どおりにSTDINからSTDOUTへの処理が続行されます。

-iまた、withオプションを使用する理由、-pまたはprint内部編集が必要な場合に明示的なステートメントを使用する理由も説明します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

関連情報