web-dev-qa-db-ja.com

ファイルを置き換えるときにファイルのアクセス許可を維持(または復元)する

ファイルを引数として受け入れ、ファイルを変更して、2番目の引数で指定されたファイル名に書き込むコマンドがあります。そのプログラムをmodifyfileと呼びます。

「そのまま」動作するようにしたいので、一時ファイルに変更してから戻すシェルスクリプト(bash)を作成しました。

TMP=`mktemp`
modifyfile "$original" "$TMP"
mv -v "$TMP" "$original"

これには、このファイルの権限を破壊するという残念な副作用があります。ファイルはデフォルトの権限で再作成されます。

mvコマンドに、アクセス許可を変更せずに宛先を上書きするように指示する方法はありますか?または、元のユーザー、グループ、および権限を保存して復元する方法はありますか?

11

mvを使用する代わりに、catをリダイレクトするだけです。例えば:

TMP=$(mktemp)
modifyfile "$original" "$TMP"
cat "$TMP" > "$original"

これにより、$original$TMPの内容で上書きされ、ファイルレベルでは何も変更されません。

10
strugee

ファイルを新しいバージョンで置き換える方法は2つあります。

  1. 新しいバージョンで一時ファイルを作成し、適切な場所に移動します。

    • 利点:プログラムがそのファイルを開く場合、移動の前または後にファイルを開いたかどうかに応じて、古いコンテンツまたは新しいコンテンツを読み取ります。取り違えはありません。
    • 利点:クラッシュした場合、古いコンテンツが保持されます。
    • 欠点:新しいファイルが作成されるため、ファイルの属性(所有権、権限など)は保持されません。
  2. 古いファイルを上書きします。

    • 利点:ファイルの属性が保持されます。
    • 欠点:クラッシュした場合、ファイルが半分書き込まれたままになることがあります。
    • 欠点:更新中にプログラムがファイルを開いていると、このプログラムは一貫性のないデータを読み取る可能性があります。

可能であれば、方法1を使用しますが、最初に元のファイルの属性をcp -p --attributes-onlyで複製します。これにはGNU coreutilsが必要です(つまり、非組み込みLinux、または十分にLinuxに似た環境)。cp--attributes-onlyがない場合は、このオプションを省略してください:動作しますが、データも複製されます。

tmp=$(mktemp)
cp -p --attributes-only "$original" "$tmp"
modifyfile "$original" "$tmp"
mv -f "$tmp" "$original"

既存のファイルの属性を複製できない場合(たとえば、ファイルに対する書き込み権限はあるが所有しておらず、所有者を保持したい場合)は、方法2のみが可能です。データ損失のリスクを最小限に抑えるには:

  • ファイルが不完全になるウィンドウをできるだけ小さくします。最初に一時ファイルでデータを準備してから、所定の場所にコピーします。
  • 最初に古いファイルのバックアップを作成します。
tmp=$(mktemp)
backup="${original}~"
modifyfile "$original" "$tmp"
cp -p "$original" "$backup"
cp -f "$tmp" "$original"

最初の回答について話し合った後、別の回答を提案します。

_TMP="$(mktemp "$original".XXXXXXXXXX)"
modifyfile "$original" "$TMP"
chmod --reference="$original" "$TMP"
chown --reference="$original" "$TMP"
mv -f "$TMP" "$original"
_

備考:

  • 一時ファイルが_$original_ではなく_/tmp_と同じフォルダーに配置されるように、mktempテンプレートで_$original_を使用しています。 _/tmp_が別のファイルシステムにマウントされている場合、操作はアトミックではなくなると思います。
  • 空白が含まれている場合に備えて、mktempの結果が引用されるようになりました。
  • 私は ``の代わりに$()を使用しています。
  • _ch{mod,own} --reference_は、_$original_の権限を_$TMP_に転送するために使用されます。誰かがメタデータで転送できる、また転送すべきであるという追加のアイデアを持っている場合は、投稿を編集して追加してください。
  • ああ、ジルが指摘したように、これにはルート権限が必要です。まあ、私はこれを書いたので、これを破棄するつもりはありません:P
5