Dosyayı değiştirirken dosya izinlerini koru (veya geri yükle)


11

Bir dosyayı bağımsız değişken olarak kabul eden, dosyayı değiştiren, daha sonra ikinci bağımsız değişkende belirtilen dosya adına yazan bir komut var. O programı arayacağım modifyfile.

Ben geçici bir dosyaya değiştirir sonra geri taşır bir kabuk komut dosyası (bash) yazdı "yerinde" çalışmak istedim:

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

Bunun, bu dosyadaki izinleri yok etmenin talihsiz yan etkisi vardır. Dosya varsayılan izinlerle yeniden oluşturulur.

mvKomutun, hedefini izinlerini değiştirmeden üzerine yazmasını söylemenin bir yolu var mı ? Ya da alternatif olarak kullanıcıyı, grubu ve izinleri orijinalden kaydetmenin ve geri yüklemenin bir yolu var mı?

Yanıtlar:


10

Kullanmak yerine mv, sadece yönlendirin cat. Örneğin:

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

Bu , dosya düzeyindeki hiçbir şeye dokunmadan $originaliçeriğinin üzerine yazar $TMP.


Bazı programların dosyada açık dosya tanıtıcısı varsa bu sorunlu olamaz mı?
Martin von Wittich

2
O zaman ben de yapmak zorundayım rm "$TMP", ama istediğim şeyi yapıyor gibi görünüyor.
Stephen Ostermiller

@MartinvonWittich bunun yerine muhtemelen bir sorun olurdu mv. Bu sorunu çözmenin bir yolunu göremiyorum.
Strugee

2
@MartinvonWittich Evet. Create-new-then-move size atomik bir değişiklik sağlar ve dosyayı açık olan programları etkilemez, ancak yeni bir dosya oluşturduğundan dosyanın sahipliği ve izinleri kaybolur. Kesme-mevcut-sonra-yazma izinleri ve sahipliği korur, ancak bir çökme durumunda veri kaybeder ve dosyayı açık olan programların ayakları altında halıyı kaydırır. Her ikisinin de iyi kısımlarını birleştiremezsiniz.
Gilles 'SO- kötü olmayı kes

1
@MartinvonWittich chownsadece kök olarak çalışır. chmodve chgrpkullanıcının izinlerine bağlı olarak çalışabilir veya çalışmayabilir. ACL veya dosya sistemine özgü genişletilmiş öznitelikler gibi diğer öznitelikleri de kopyalamaz.
Gilles 'SO- kötü olmayı kes

10

Bir dosyayı yeni bir sürümle değiştirmek için iki strateji vardır:

  1. Yeni sürümle geçici bir dosya oluşturun, ardından yerine taşıyın.

    • Avantaj: Bir program bu dosyayı açarsa, dosyayı taşımadan önce veya sonra açmasına bağlı olarak eski içeriği veya yeni içeriği okuyacaktır. Karışım yok.
    • Avantajı: Bir kilitlenme durumunda eski içerik korunur.
    • Dezavantajı: Yeni bir dosya oluşturulduğundan, dosyanın öznitelikleri (sahiplik, izin vb.) Korunmaz.
  2. Eski dosyanın üzerine yazın.

    • Avantajı: Dosyanın öznitelikleri korunur.
    • Dezavantajı: Bir çökme durumunda, dosya yarı yazılı olarak bırakılabilir.
    • Dezavantajı: Bir program güncellenirken dosyayı açıksa, bu program tutarsız verileri okuyabilir.

Yapabiliyorsanız, yöntem 1'i kullanın, ancak önce orijinal dosyanın özniteliklerini ile çoğaltın cp -p --attributes-only. Bu, GNU coreutils (yani gömülü olmayan Linux veya yeterince Linux benzeri ortamlar) gerektirir. Sahip değilseniz cp, --attributes-onlybu seçeneği atlayın: işe yarayacak, ancak verileri de çoğaltacaktır.

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

Varolan dosyanın özniteliklerini çoğaltamazsanız, örneğin üzerine yazma izniniz olduğu, ancak sahip olmadığınız ve sahibini korumak istediğiniz için, yalnızca yöntem 2 mümkündür. Veri kaybı riskini en aza indirmek için:

  • Dosyanın eksik kaldığı pencereyi olabildiğince küçük hale getirin. Önce verileri geçici bir dosyada hazırlayın, sonra yerine kopyalayın.
  • Önce eski dosyanın yedeğini alın.

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

Güzel cevap! Bugünlerde argümanı kullanarak öneririm --attributes okunur ile cp komutunu Yöntem 1 . Bu şekilde, cp -p --attributes-only "$original" "$tmp"dosyanın içeriğini kopyalamak için kaynaklar kullanılmaz. Bu argümanın hangi sürümden eklendiğini bulamadım.
Marcelo Barros

@MarceloBarros 2010-10-15 yayınlanmış GNU coreutils 8.6 eklendi, bu nedenle bu günlerde GNU coreutils varsa sahip olmalısınız. Diğer cpuygulamalarda hala böyle bir şey yok .
Gilles 'SO- kötü olmayı bırak

5

İlk cevap üzerine yaptığımız tartışmadan sonra farklı bir cevap öneriyorum:

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

Uyarılar:

  • Kullandığım $originaliçinde mktempgeçici dosya yerleştirilir emin olmak için şablonun /tmpama aynı klasörde $original. /tmpFarklı bir dosya sistemine monte edilirse , işlemin artık atomik olmayacağına inanıyorum.
  • Sonucu mktempşimdi alıntı durumunda o boşluk içerir.
  • Bunun $()yerine `` daha temiz olduğunu düşündüğüm için kullanıyorum.
  • ch{mod,own} --referenceizinlerini aktarmak için kullanılır $originaliçin $TMP. Birisi hangi meta verilerin aktarılabileceği ve aktarılması gerektiği konusunda ek fikirleri varsa, lütfen yazımı düzenleyin ve ekleyin.
  • Oh, Gilles'in işaret ettiği gibi bu, kök izinleri gerektiriyor. Şimdi yazdığım için bunu atmayacağım: P
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.