Genel olarak dosyaların değiştirilmesi
İlk olarak, bir dosyayı değiştirmek için birkaç strateji vardır:
Varolan dosyayı yazmak için açın , 0 uzunluğa kısaltın ve yeni içeriği yazın. (Daha az yaygın olan bir varyant, mevcut dosyayı açmak, eski içeriğin üzerine yeni içerik yazmak, daha kısaysa dosyayı yeni uzunluğa kısaltmaktır.) Kabuk terimlerinde:
echo 'new content' >somefile
Eski dosyayı kaldırın ve aynı adla yeni bir dosya oluşturun. Kabuk terimleriyle:
rm somefile
echo 'new content' >somefile
Geçici bir adla yeni bir dosyaya yazın, ardından yeni dosyayı mevcut ada taşıyın . Taşıma eski dosyayı siler. Kabuk terimleriyle:
echo 'new content' >somefile.new
mv somefile.new somefile
Stratejiler arasındaki tüm farklılıkları listelemeyeceğim, burada önemli olanlardan bahsedeceğim. Stategy 1 ile, herhangi bir işlem şu anda dosyayı kullanıyorsa, işlem yeni içeriği güncellenirken görür. İşlem dosya içeriğinin aynı kalmasını beklerse, bu biraz karışıklığa neden olabilir. Bunun yalnızca dosyayı açık olan işlemlerde (içinde lsof
veya içinde görüldüğü gibi ; bir belgenin açık olduğu etkileşimli uygulamaların (örneğin bir düzenleyicide bir dosyayı açma) genellikle dosyayı açık tutmadığını, dosya içeriğini “Belgeyi aç” işlemi yapılır ve “belgeyi kaydet” işlemi sırasında dosyayı (yukarıdaki stratejilerden birini kullanarak) değiştirirler./proc/PID/fd/
Strateji 2 ve 3'te, bazı işlemlerde dosya somefile
açıksa, içerik yükseltme sırasında eski dosya açık kalır. 2. strateji ile, dosyayı kaldırma adımı yalnızca dosyanın dizindeki girişini kaldırır. Dosyanın kendisi yalnızca kendisine yol açan dizin girişi olmadığında (tipik Unix dosya sistemlerinde, aynı dosya için birden fazla dizin girişi olabilir ) ve hiçbir işlemin açık olmadığı durumlarda kaldırılır . İşte bunu gözlemlemenin bir yolu - dosya yalnızca sleep
işlem öldürüldüğünde kaldırılır ( rm
yalnızca dizin girişini kaldırır).
echo 'old content' >somefile
sleep 9999999 <somefile &
df .
rm somefile
df .
cat /proc/$!/fd/0
kill $!
df .
Strateji 3 ile, yeni dosyayı mevcut isme taşıma adımı eski içeriğe giden dizin girişini kaldırır ve yeni içeriğe giden bir dizin girişi oluşturur. Bu bir atomik işlemle yapılır, bu nedenle bu stratejinin büyük bir avantajı vardır: bir işlem dosyayı herhangi bir zamanda açarsa, eski içeriği veya yeni içeriği görecektir - karışık içerik alma riski yoktur veya dosya mevcut.
Yürütülebilir dosyaları değiştirme
Linux'ta çalışan bir yürütülebilir programla strateji 1'i denerseniz bir hata alırsınız.
cp /bin/sleep .
./sleep 999999 &
echo oops >|sleep
bash: sleep: Text file busy
“Metin dosyası” , belirsiz tarihsel nedenlerden dolayı yürütülebilir kod içeren bir dosya anlamına gelir . Linux, diğer birçok unix varyantı gibi, çalışan bir programın kodunun üzerine yazmayı reddediyor; birkaç unix varyantı buna izin verir ve yeni kod eski kodda çok iyi bir değişiklik olmadığı sürece çökmelere neden olur.
Linux'ta, dinamik olarak yüklenen bir kitaplığın kodunun üzerine yazabilirsiniz. Kullanan programın çökmesine neden olması muhtemeldir. (Bunu izleyemeyebilirsiniz, sleep
çünkü başladığında ihtiyaç duyduğu tüm kütüphane kodunu yükler. Uyuduktan sonra faydalı bir şey yapan daha karmaşık bir program deneyin perl -e 'sleep 9; print lc $ARGV[0]'
.)
Bir tercüman komut dosyası çalıştırıyorsa, komut dosyası dosya yorumlayıcısı tarafından normal bir şekilde açılır, bu nedenle komut dosyasının üzerine yazılmasına karşı koruma yoktur. Bazı tercümanlar ilk satırı yürütmeye başlamadan önce tüm komut dosyasını okur ve ayrıştırır, diğerleri ise komut dosyasını gerektiği gibi okur. Bkz. Bir komut dosyasını yürütme sırasında düzenlerseniz ne olur? ve Linux kabuk komut dosyalarıyla nasıl başa çıkıyor? daha fazla ayrıntı için.
2. ve 3. stratejiler yürütülebilir dosyalar için de güvenlidir: yürütülebilir dosyalar (ve dinamik olarak yüklenmiş kütüphaneler) bir dosya tanıtıcısı olması açısından açık dosyalar olmamasına rağmen çok benzer şekilde davranırlar. Bazı program kodu çalıştırdığı sürece, dosya bir dizin girişi olmasa bile diskte kalır.
Bir uygulamayı yükseltme
Çoğu paket yöneticisi, yukarıda belirtilen büyük avantajdan dolayı dosyaları değiştirmek için strateji 3'ü kullanır - herhangi bir zamanda dosyayı açmak geçerli bir sürümüne yol açar.
Uygulama yükseltmelerinin kesilebileceği yerlerde, bir dosyayı yükseltmek atomikken, uygulamanın bir bütün olarak yükseltilmesi, uygulamanın birden fazla dosyadan (program, kütüphaneler, veriler, ...) oluşması değildir. Aşağıdaki olay sırasını göz önünde bulundurun:
- Uygulamanın bir örneği başlatılır.
- Uygulama yükseltildi.
- Çalışan örnek uygulaması veri dosyalarından birini açar.
3. adımda, uygulamanın eski sürümünün çalışan örneği, yeni sürümden bir veri dosyası açar. Bunun işe yarayıp yaramadığı uygulamaya, hangi dosyanın olduğuna ve dosyanın ne kadar değiştirildiğine bağlıdır.
Yükseltme işleminden sonra eski programın hala çalıştığını göreceksiniz. Yeni sürümü çalıştırmak istiyorsanız, eski programdan çıkmanız ve yeni sürümü çalıştırmanız gerekir. Paket yöneticileri genellikle yükseltme işleminde cinleri öldürür ve yeniden başlatır, ancak son kullanıcı uygulamalarını tek başına bırakır.
Birkaç artalan sürecinin, artalan sürecini öldürmek ve yeni örneğin yeniden başlatılmasını beklemek zorunda kalmadan yükseltmeleri işlemek için özel prosedürleri vardır (bu, hizmet kesintisine neden olur). Bu öldürülemeyen init durumunda gereklidir ; init sistemleri, çalışan örnek çağrısının execve
kendisini yeni sürümle değiştirmesini istemek için bir yol sağlar .