सामान्य रूप से फ़ाइलों को बदलना
सबसे पहले, फ़ाइल को बदलने के लिए कई रणनीतियाँ हैं:
लिखने के लिए मौजूदा फ़ाइल खोलें , इसे 0 लंबाई में काटें, और नई सामग्री लिखें। (एक कम सामान्य संस्करण मौजूदा फ़ाइल को खोलने के लिए है, नई सामग्री के साथ पुरानी सामग्री को अधिलेखित करें, फ़ाइल को छोटी होने पर नई लंबाई तक काट दें।) शेल शब्दों में:
echo 'new content' >somefile
पुरानी फ़ाइल को निकालें , और उसी नाम से एक नई फ़ाइल बनाएँ। शेल शब्दों में:
rm somefile
echo 'new content' >somefile
एक अस्थायी नाम के तहत एक नई फ़ाइल में लिखें, तो ले जाने के मौजूदा नाम करने के लिए नई फ़ाइल। कदम पुरानी फ़ाइल को हटा देता है। शेल शब्दों में:
echo 'new content' >somefile.new
mv somefile.new somefile
मैं रणनीतियों के बीच सभी अंतरों को सूचीबद्ध नहीं करूंगा, मैं बस कुछ का उल्लेख करूंगा जो यहां महत्वपूर्ण हैं। स्टैगेटी 1 के साथ, यदि कोई प्रक्रिया वर्तमान में फ़ाइल का उपयोग कर रही है, तो यह प्रक्रिया नई सामग्री को देखती है क्योंकि यह अपडेट हो रही है। यदि प्रक्रिया फ़ाइल सामग्री के समान रहने की अपेक्षा करती है तो यह कुछ भ्रम पैदा कर सकता है। ध्यान दें कि यह केवल उन प्रक्रियाओं के बारे में है, जिनके पास फ़ाइल खुली हुई है (जैसा कि दिखाई दे रहा है lsof
या अंदर है ; इंटरैक्टिव एप्लिकेशन जिनके पास एक दस्तावेज़ खुला है (जैसे संपादक में फ़ाइल खोलना) आमतौर पर फ़ाइल को खुला नहीं रखते हैं, वे फ़ाइल सामग्री को लोड करते हैं "ओपन डॉक्यूमेंट" ऑपरेशन और वे "सेव डॉक्यूमेंट" ऑपरेशन के दौरान फाइल (ऊपर दी गई रणनीतियों में से एक का उपयोग करके) को बदलते हैं।/proc/PID/fd/
रणनीतियों 2 और 3 के साथ, यदि कुछ प्रक्रिया में फ़ाइल somefile
खुली है, तो पुरानी फ़ाइल सामग्री के उन्नयन के दौरान खुली रहती है। रणनीति 2 के साथ, वास्तव में फ़ाइल को हटाने का चरण केवल निर्देशिका में फ़ाइल की प्रविष्टि को हटाता है। फ़ाइल को केवल तभी हटाया जाता है जब उसके पास कोई निर्देशिका प्रविष्टि नहीं होती है, जिसके कारण उस पर जाता है (विशिष्ट यूनिक्स फाइल सिस्टम पर, एक ही फ़ाइल के लिए एक से अधिक निर्देशिका प्रविष्टि हो सकती है ) और कोई प्रक्रिया नहीं खुली है। यहां इसका अवलोकन करने का एक तरीका है - फ़ाइल केवल तभी निकाली जाती है जब sleep
प्रक्रिया को मार दिया जाता है ( rm
केवल इसकी निर्देशिका प्रविष्टि को हटा दिया जाता है)।
echo 'old content' >somefile
sleep 9999999 <somefile &
df .
rm somefile
df .
cat /proc/$!/fd/0
kill $!
df .
रणनीति 3 के साथ, नई फ़ाइल को मौजूदा नाम पर ले जाने का चरण पुरानी सामग्री के लिए निर्देशिका प्रविष्टि को हटाता है और नई सामग्री के लिए अग्रणी निर्देशिका प्रविष्टि बनाता है। यह एक परमाणु संचालन में किया जाता है, इसलिए इस रणनीति का एक बड़ा फायदा होता है: यदि किसी भी समय फ़ाइल एक प्रक्रिया को खोलती है, तो यह या तो पुरानी सामग्री या नई सामग्री को देखेगा - मिश्रित सामग्री या फ़ाइल नहीं होने का कोई जोखिम नहीं है मौजूदा।
क्रियान्वयन की जगह
यदि आप लिनक्स पर चल रहे निष्पादन योग्य के साथ रणनीति 1 की कोशिश करते हैं, तो आपको एक त्रुटि मिलेगी।
cp /bin/sleep .
./sleep 999999 &
echo oops >|sleep
bash: sleep: Text file busy
एक "पाठ फ़ाइल" का अर्थ अस्पष्ट ऐतिहासिक कारणों के लिए निष्पादन योग्य कोड वाली फ़ाइल है । लिनक्स, कई अन्य यूनिक्स वेरिएंट की तरह, एक चल रहे प्रोग्राम के कोड को ओवरराइट करने से इनकार करता है; कुछ यूनिक्स वेरिएंट इसकी अनुमति देते हैं, जब तक कि नया कोड पुराने कोड के एक बहुत अच्छी तरह से संशोधित संशोधन नहीं हो जाता है।
लिनक्स पर, आप गतिशील रूप से भरी हुई लाइब्रेरी के कोड को ओवरराइट कर सकते हैं। इसका उपयोग करने वाले प्रोग्राम के क्रैश होने की संभावना है। (आप इसे इसलिए नहीं देख सकते sleep
क्योंकि यह शुरू होने पर इसकी आवश्यकता वाले सभी लाइब्रेरी कोड को लोड करता है। अधिक जटिल प्रोग्राम आज़माएं जो सोने के बाद कुछ उपयोगी हो, जैसे perl -e 'sleep 9; print lc $ARGV[0]'
।)
यदि कोई दुभाषिया स्क्रिप्ट चला रहा है, तो दुभाषिया द्वारा स्क्रिप्ट फ़ाइल को साधारण तरीके से खोला जाता है, इसलिए स्क्रिप्ट को ओवरराइट करने से कोई सुरक्षा नहीं है। कुछ व्याख्याकार पूरी लाइन को निष्पादित करने से पहले पूरी स्क्रिप्ट को पढ़ते हैं और पार्स करते हैं, अन्य लोग आवश्यकतानुसार स्क्रिप्ट पढ़ते हैं। देखें यदि आप निष्पादन के दौरान एक स्क्रिप्ट संपादित क्या होता है? और लिनक्स शेल स्क्रिप्ट के साथ कैसे व्यवहार करता है? अधिक जानकारी के लिए।
रणनीतियाँ 2 और 3 निष्पादनयोग्य के लिए भी सुरक्षित हैं: हालाँकि निष्पादन योग्य (और गतिशील रूप से भरी हुई लाइब्रेरी) फ़ाइल डिस्क्रिप्टर होने के अर्थ में फ़ाइलें नहीं खुली हैं, वे बहुत ही समान तरीके से व्यवहार करते हैं। जब तक कोई प्रोग्राम कोड चला रहा होता है, तब तक फ़ाइल बिना डिस्क प्रविष्टि के भी डिस्क पर रहती है।
किसी एप्लिकेशन को अपग्रेड करना
अधिकांश पैकेज प्रबंधक फ़ाइलों को बदलने के लिए रणनीति 3 का उपयोग करते हैं, क्योंकि ऊपर उल्लिखित प्रमुख लाभ - किसी भी समय, फ़ाइल को खोलने से इसका एक वैध संस्करण होता है।
जहां एप्लिकेशन अपग्रेड टूट सकता है, वह यह है कि एक फ़ाइल को अपग्रेड करते समय, एप्लिकेशन को अपग्रेड करना एक संपूर्ण के रूप में है यदि एप्लिकेशन में कई फाइलें (प्रोग्राम, लाइब्रेरी, डेटा,…) शामिल नहीं हैं। घटनाओं के निम्नलिखित अनुक्रम पर विचार करें:
- आवेदन का एक उदाहरण शुरू होता है।
- एप्लिकेशन अपग्रेड किया गया है।
- रनिंग इंस्टेंस एप्लिकेशन इसकी एक डेटा फ़ाइल खोलता है।
चरण 3 में, एप्लिकेशन के पुराने संस्करण की चल रही आवृत्ति नए संस्करण से डेटा फ़ाइल खोल रही है। यह काम करता है या नहीं यह आवेदन पर निर्भर करता है कि यह किस फ़ाइल का है और फ़ाइल को कितना संशोधित किया गया है।
अपग्रेड के बाद, आप ध्यान देंगे कि पुराना प्रोग्राम अभी भी चल रहा है। यदि आप नया संस्करण चलाना चाहते हैं, तो आपको पुराने कार्यक्रम से बाहर निकलकर नया संस्करण चलाना होगा। पैकेज प्रबंधक आमतौर पर एक अपग्रेड पर डेमॉन को मारते हैं और पुनः आरंभ करते हैं, लेकिन एंड-यूज़र एप्लिकेशन को अकेले छोड़ देते हैं।
कुछ डेमॉन के पास डेमन को मारने के लिए अपग्रेड को संभालने के लिए विशेष प्रक्रियाएं हैं और नए उदाहरण के फिर से शुरू होने का इंतजार करते हैं (जो एक सेवा व्यवधान का कारण बनता है)। Init के मामले में यह आवश्यक है , जिसे मारा नहीं जा सकता है; init सिस्टम अनुरोध करने का एक तरीका प्रदान करता है कि रनिंग इंस्टेंस execve
नए संस्करण के साथ खुद को बदलने के लिए कॉल करता है।