यूनिक्स में, अधिकांश संपादक एक नई अस्थायी फ़ाइल बनाते हैं जिसमें संपादित सामग्री होती है। जब संपादित फ़ाइल सहेज ली जाती है, तो मूल फ़ाइल हटा दी जाती है और अस्थायी फ़ाइल का नाम बदलकर मूल नाम रख दिया जाता है। (निश्चित रूप से, डटलॉस को रोकने के लिए विभिन्न सुरक्षा उपाय हैं।) यह उदाहरण के लिए, ("इन-प्लेस") झंडे के साथ sed
या perl
जब इनवाइस किया जाता है -i
, जो वास्तव में "इन-प्लेस" नहीं है। इसे "पुराने नाम के साथ नया स्थान" कहा जाना चाहिए था।
यह अच्छी तरह से काम करता है क्योंकि यूनिक्स आश्वासन देता है (कम से कम स्थानीय फाइल सिस्टम के लिए) कि एक खुली हुई फ़ाइल तब तक मौजूद रहती है जब तक कि इसे बंद नहीं किया जाता है, भले ही यह "हटा दिया गया" हो और उसी नाम से एक नई फ़ाइल बनाई गई हो। (यह संयोग की बात नहीं है कि एक फाइल को "डिलीट" करने के लिए यूनिक्स सिस्टम कॉल वास्तव में "अनलिंक" कहलाता है।) इसलिए, आम तौर पर बोलना, यदि शेल दुभाषिया में कुछ स्रोत फ़ाइल खुली है, और आप फ़ाइल को ऊपर वर्णित तरीके से "संपादित" करते हैं। शेल में तब भी परिवर्तन दिखाई नहीं देगा क्योंकि इसमें अभी भी मूल फ़ाइल खुली है।
[नोट: सभी मानकों-आधारित टिप्पणियों के साथ, उपरोक्त कई व्याख्याओं के अधीन है और विभिन्न कोने-मामले हैं, जैसे कि एनएफएस। अपवाद के साथ टिप्पणियों को भरने के लिए बच्चों का स्वागत है।]
यह निश्चित रूप से, सीधे फ़ाइलों को संशोधित करने के लिए संभव है; यह संपादन उद्देश्यों के लिए बहुत सुविधाजनक नहीं है, क्योंकि जब आप किसी फ़ाइल में डेटा को अधिलेखित कर सकते हैं, तो आप सभी निम्नलिखित डेटा को शिफ्ट किए बिना हटा या सम्मिलित नहीं कर सकते हैं, जो कि काफी पुनर्लेखन होगा। इसके अलावा, जब आप उस स्थानांतरण को कर रहे थे, तो फ़ाइल की सामग्री अप्रत्याशित होगी और जिन प्रक्रियाओं में फ़ाइल खुली थी, उन्हें नुकसान होगा। इस के साथ (उदाहरण के लिए, डेटाबेस सिस्टम के साथ) दूर होने के लिए, आपको संशोधन प्रोटोकॉल और वितरित ताले के परिष्कृत सेट की आवश्यकता है; सामान जो एक विशिष्ट फ़ाइल संपादन उपयोगिता के दायरे से परे है।
इसलिए, यदि आप शेल द्वारा संसाधित होने के दौरान फ़ाइल को संपादित करना चाहते हैं, तो आपके पास दो विकल्प हैं:
आप फ़ाइल में संलग्न कर सकते हैं। यह हमेशा काम करना चाहिए।
आप फ़ाइल को उसी लंबाई की नई सामग्री के साथ अधिलेखित कर सकते हैं । यह कार्य हो सकता है या नहीं, इस पर निर्भर करता है कि शेल फ़ाइल के उस हिस्से को पहले ही पढ़ चुका है या नहीं। चूंकि अधिकांश फ़ाइल I / O में पढ़ने वाले बफ़र्स शामिल हैं, और चूंकि सभी गोले मुझे पता है कि इसे निष्पादित करने से पहले एक संपूर्ण यौगिक कमांड पढ़ा जाता है, यह बहुत संभावना नहीं है कि आप इस से दूर हो सकते हैं। यह निश्चित रूप से विश्वसनीय नहीं होगा।
मैं Posix मानक में किसी भी शब्द के बारे में नहीं जानता, जिसके लिए फ़ाइल को निष्पादित करते समय वास्तव में एक स्क्रिप्ट फ़ाइल में संलग्न होने की संभावना की आवश्यकता होती है, इसलिए यह हर Posix अनुरूप शेल के साथ काम नहीं कर सकता है, लगभग वर्तमान की पेशकश के साथ बहुत कम- और कभी-कभी-पॉज़िक्स-कंप्लीट गोले। तो YMMV। लेकिन जहां तक मुझे पता है, यह बैश के साथ मज़बूती से काम करता है।
सबूत के रूप में, यहां बैश में बीयर कार्यक्रम की कुख्यात 99 बोतलों का "लूप-मुक्त" कार्यान्वयन है, जो dd
ओवरराइट करने और अपेंड करने के लिए उपयोग करता है (ओवरराइटिंग संभवतः सुरक्षित है क्योंकि यह वर्तमान में निष्पादित लाइन को प्रतिस्थापित करता है, जो हमेशा की अंतिम पंक्ति होती है। फ़ाइल, बिल्कुल समान लंबाई की टिप्पणी के साथ; मैंने ऐसा इसलिए किया ताकि अंतिम परिणाम को आत्म-संशोधित व्यवहार के बिना निष्पादित किया जा सके।)
#!/bin/bash
if [[ $1 == reset ]]; then
printf "%s\n%-16s#\n" '####' 'next ${1:-99}' |
dd if=/dev/stdin of=$0 seek=$(grep -bom1 ^#### $0 | cut -f1 -d:) bs=1 2>/dev/null
exit
fi
step() {
s=s
one=one
case $beer in
2) beer=1; unset s;;
1) beer="No more"; one=it;;
"No more") beer=99; return 1;;
*) ((--beer));;
esac
}
next() {
step ${beer:=$(($1+1))}
refrain |
dd if=/dev/stdin of=$0 seek=$(grep -bom1 ^next\ $0 | cut -f1 -d:) bs=1 conv=notrunc 2>/dev/null
}
refrain() {
printf "%-17s\n" "# $beer bottles"
echo echo ${beer:-No more} bottle$s of beer on the wall, ${beer:-No more} bottle$s of beer.
if step; then
echo echo Take $one down, pass it around, $beer bottle$s of beer on the wall.
echo echo
echo next abcdefghijkl
else
echo echo Go to the store, buy some more, $beer bottle$s of beer on the wall.
fi
}
####
next ${1:-99} #