Pertahankan (atau pulihkan) izin file saat mengganti file


11

Saya memiliki perintah yang menerima file sebagai argumen, memodifikasi file, lalu menulisnya ke nama file yang ditentukan dalam argumen kedua. Saya akan memanggil program itu modifyfile.

Saya ingin ini berfungsi "di tempat" jadi saya menulis skrip shell (bash) yang mengubahnya menjadi file sementara lalu memindahkannya kembali:

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

Ini memiliki efek samping yang tidak diinginkan yaitu menghancurkan izin pada file ini. File dibuat ulang dengan izin default.

Apakah ada cara untuk memberi tahu mvperintah untuk menimpa tujuan tanpa mengubah izinnya? Atau bergantian apakah ada cara untuk menyelamatkan pengguna, grup, dan permisisi dari yang asli dan memulihkannya?

Jawaban:


10

Alih-alih menggunakan mv, arahkan saja cat. Sebagai contoh:

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

Ini menimpa $originaldengan konten $TMP, tanpa menyentuh apa pun di tingkat file.


Tidak bisakah itu menjadi masalah jika beberapa program memiliki file terbuka menangani file?
Martin von Wittich

2
Saya kemudian harus rm "$TMP"juga, tetapi tampaknya melakukan apa yang saya inginkan.
Stephen Ostermiller

@ MartinvonWittich mungkin akan menjadi masalah jika Anda menggunakannya mvsebagai gantinya. Saya tidak melihat cara untuk menyelesaikan masalah itu.
strugee

2
@MartinvonWittich Ya. Buat-baru-lalu-pindah memberi Anda perubahan atom dan tidak memengaruhi program yang membuka file, tetapi karena membuat file baru, kepemilikan dan izin file akan hilang. Truncate-existing-then-write mempertahankan izin dan kepemilikan tetapi kehilangan data jika terjadi kerusakan dan menggesekkan karpet di bawah kaki program yang memiliki file terbuka. Anda tidak dapat menggabungkan bagian-bagian yang baik dari keduanya.
Gilles 'SO- stop being evil'

1
@MartinvonWittich chownhanya berfungsi sebagai root. chmoddan chgrpmungkin atau mungkin tidak berfungsi tergantung pada izin pengguna. Baik menyalin atribut lain seperti ACL atau atribut diperluas khusus sistem file.
Gilles 'SO- stop being evil'

10

Ada dua strategi untuk mengganti file dengan versi baru:

  1. Buat file sementara dengan versi baru, lalu pindahkan ke tempatnya.

    • Keuntungan: jika suatu program membuka file itu, itu akan membaca konten lama atau konten baru, tergantung pada apakah itu membuka file sebelum atau setelah pindah. Tidak ada campur aduk.
    • Keuntungan: jika terjadi kerusakan, konten lama dipertahankan.
    • Kelemahan: karena file baru dibuat, atribut file (kepemilikan, izin, dll.) Tidak dipertahankan.
  2. Timpa file lama di tempatnya.

    • Keuntungan: atribut file dipertahankan.
    • Kelemahan: jika terjadi kerusakan, file mungkin dibiarkan setengah ditulis.
    • Kelemahan: jika suatu program membuka file ketika sedang diperbarui, program ini mungkin membaca data yang tidak konsisten.

Jika Anda bisa, gunakan metode 1, tetapi pertama-tama salin atribut dengan file asli cp -p --attributes-only. Ini membutuhkan GNU coreutils (yaitu Linux yang tidak tertanam, atau lingkungan yang cukup seperti Linux). Jika Anda cptidak memilikinya --attributes-only, abaikan opsi ini: itu akan berfungsi tetapi itu akan mereplikasi data juga.

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

Jika Anda tidak dapat mereplikasi atribut dari file yang ada, misalnya karena Anda memiliki izin tulis tetapi tidak memilikinya dan Anda ingin mempertahankan pemiliknya, maka hanya metode 2 yang memungkinkan. Untuk meminimalkan risiko kehilangan data:

  • Buatlah jendela di mana file tersebut tidak lengkap sekecil mungkin. Siapkan data terlebih dahulu dalam file sementara, lalu salin ke tempatnya.
  • Buat cadangan file lama terlebih dahulu.

tmp=$(mktemp)
backup="${original}~"
modifyfile "$original" "$tmp"
cp -p "$original" "$backup"
cp -f "$tmp" "$original"

Jawaban bagus! Saat ini saya menyarankan menggunakan argumen --attributes-only dengan perintah cp di Metode 1 . Dengan cara ini, cp -p --attributes-only "$original" "$tmp"tidak akan menggunakan sumber daya untuk menyalin konten file. Saya tidak dapat menemukan dari versi mana argumen ini ditambahkan.
Marcelo Barros

@MarceloBarros Itu ditambahkan di GNU coreutils 8.6 dirilis 2010-10-15, jadi hari ini jika Anda memiliki GNU coreutils Anda harus memilikinya. Masih tidak ada hal seperti itu dengan cpimplementasi lain .
Gilles 'SO- berhenti bersikap jahat'

5

Setelah diskusi kami tentang jawaban pertama, saya mengusulkan jawaban yang berbeda:

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

Catatan:

  • Saya menggunakan $originaldalam mktemptemplate untuk memastikan bahwa file sementara tidak ditempatkan /tmptetapi dalam folder yang sama dengan $original. Saya percaya bahwa jika /tmpdipasang pada sistem file yang berbeda operasi tidak akan lagi menjadi atom.
  • Hasilnya mktempsekarang dikutip jika mengandung spasi.
  • Saya menggunakan $()bukan `` karena saya menganggapnya lebih bersih.
  • ch{mod,own} --referencedigunakan untuk mentransfer izin $originaluntuk $TMP. Jika seseorang memiliki ide tambahan tentang metadata apa yang dapat dan harus ditransfer, maka silakan edit posting saya dan tambahkan.
  • Oh well, ini membutuhkan izin root seperti yang ditunjukkan Gilles. Yah, saya tidak akan membuang ini sekarang karena saya sudah menulisnya: P
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.