मैं sed -i (इन-प्लेस संपादन) के साथ पोर्टेबिलिटी कैसे प्राप्त कर सकता हूं?


41

मैं अपने सर्वर के लिए शेल स्क्रिप्ट लिख रहा हूं, जो कि FreeBSD को चलाने वाली एक साझा होस्टिंग है। मैं अपने पीसी पर चलने वाले लिनक्स पर स्थानीय रूप से उनका परीक्षण करने में सक्षम होना चाहता हूं। इसलिए, मैं उन्हें एक पोर्टेबल तरीके से लिखने की कोशिश कर रहा हूं, लेकिन इसके साथ sedमुझे ऐसा करने का कोई रास्ता नहीं दिख रहा है।

मेरी वेबसाइट का हिस्सा उत्पन्न स्थिर HTML फ़ाइलों का उपयोग करता है, और यह पुनर्जीवन रेखा प्रत्येक उत्थान के बाद सही DOCTYPE सम्मिलित करती है:

sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}

यह sedलिनक्स पर GNU के साथ काम करता है , लेकिन FreeBSD बैकअप कॉपी के लिए एक्सटेंशन होने के sedबाद पहले तर्क की उम्मीद करता -iहै। यह इस तरह दिखेगा:

sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}

हालांकि, GNU sedबदले में तुरंत बाद की अभिव्यक्ति की अपेक्षा करता है -i। (यह भी newline हैंडलिंग के साथ सुधार की आवश्यकता है, लेकिन यह पहले से ही यहाँ में जवाब दिया है )

बेशक मैं स्क्रिप्ट के अपने सर्वर कॉपी में इस बदलाव को शामिल कर सकता हूं, लेकिन यह संस्करण के लिए वीसीएस के मेरे उपयोग को गड़बड़ करेगा। वहाँ एक पूरी तरह से पोर्टेबल तरीके से sed के साथ इसे प्राप्त करने का एक तरीका है?


आपके द्वारा प्रदत्त दो सेड स्निपेट्स समान हैं, क्या आप सुनिश्चित हैं कि कोई टाइपो नहीं है? इसके अलावा, मैं सही समय पर बैकअप एक्सटेंशन की आपूर्ति करने वाली GNU -i
सेड

Duh, इसे जगह देने के लिए धन्यवाद। मैंने अपना प्रश्न तय कर लिया है। दूसरी पंक्ति में मेरे sed में त्रुटि होती है, यह '1s / ^ / <! DOCTYPE html> \ n /' एक फ़ाइल होने की उम्मीद करता है और शिकायत करता है कि यह नहीं मिल सकता है।
लाल

जवाबों:


40

GNU sed के बाद एक वैकल्पिक एक्सटेंशन स्वीकार करता है -i। यह एक्सटेंशन एक ही तर्क में होना चाहिए जिसमें कोई हस्तक्षेप न हो। यह सिंटैक्स BSD sed पर भी काम करता है।

sed -i.bak -e '…' SOMEFILE

ध्यान दें कि बीएसडी पर, -iएकाधिक इनपुट फ़ाइलों के होने पर व्यवहार को भी बदलता है: उन्हें स्वतंत्र रूप से संसाधित किया जाता है (इसलिए जैसे $प्रत्येक फ़ाइल की अंतिम पंक्ति से मेल खाता है)। इसके अलावा यह बिजीबॉक्स पर काम नहीं करेगा।

यदि आप बैकअप फ़ाइलों का उपयोग नहीं करना चाहते हैं, तो आप जाँच सकते हैं कि किस संस्करण में सेड उपलब्ध है।

case $(sed --help 2>&1) in
  *GNU*) set sed -i;;
  *) set sed -i '';;
esac
"$@" -e '…' "$file"

या वैकल्पिक रूप से, स्थितीय मापदंडों को क्लोब करने से बचने के लिए, एक फ़ंक्शन को परिभाषित करें।

case $(sed --help 2>&1) in
  *GNU*) sed_i () { sed -i "$@"; };;
  *) sed_i () { sed -i '' "$@"; };;
esac
sed_i -e '…' "$file"

यदि आप परेशान नहीं करना चाहते हैं, तो पर्ल का उपयोग करें।

perl -i -pe '…' "$file"

यदि आप एक पोर्टेबल स्क्रिप्ट लिखना चाहते हैं, तो इसका उपयोग न करें -i- यह POSIX में नहीं है। मैन्युअल रूप से क्या हुड के तहत करता है - यह कोड की केवल एक और पंक्ति है।

sed -e '…' "$file" >"$file.new"
mv -- "$file.new" "$file"

2
जीएनयू का sed -iभी अर्थ है -s। और एक जीएनयू के लिए जांच करने का सबसे आसान तरीका कमांड के sedसाथ है sed vजो जीएनयू के लिए एक वैध शून्य है लेकिन हर जगह विफल रहता है।
मिकसेर्व

उपर्युक्त युक्तियों से प्रेरित होकर, यहां उन लोगों के लिए एक एकल-पंक्ति (यदि बदसूरत) पोर्टेबल संस्करण है, जो वास्तव में एक चाहते हैं, हालांकि यह एक सब-स्पॉन करता है: sed -i$(sed v < /dev/null 2> /dev/null || echo -n " ''") -e '...' "$file"यदि यह जीएनयू सेड नहीं है, तो इसमें दो सिंगे कोट्स के बाद एक स्थान डाला जाता है -iताकि यह हो सके बीएसडी पर काम करता है। GNU sed ही मिलता है -i
इवान एक्स

2
@IXX मैं GNU सेड के vपरीक्षण के लिए कमांड की उपस्थिति का उपयोग करने से सावधान हूँ । क्या होगा अगर फ्रीबीएसडी ने इसे लागू करने का फैसला किया?
गिल्स एसओ- बुराई को रोकना '

@ गिल्स फेयर पॉइंट, लेकिन जीएनयू सेड के लिए मैन पेज वी के ठीक उसी उद्देश्य के लिए वर्णन करता है (यह जानते हुए कि यह जीएनयू सेड है और कुछ और नहीं है), इसलिए किसी को उम्मीद होगी कि * बीएसडी उसे सम्मानित करेगा। मैं एक और परीक्षण के बारे में नहीं सोच सकता, ऑफहैंड, जो कि GNU sed पर कोई कार्रवाई नहीं करता है, जबकि BSD sed (या इसके विपरीत) पर एक त्रुटि का कारण बनता है, स्वयं का उपयोग करने के अलावा, लेकिन इसके लिए पहले एक डमी फ़ाइल बनाने की आवश्यकता होगी। उपरोक्त सीड के लिए आपका परीक्षण ठीक है लेकिन इनलाइन के लिए अनिच्छुक है। पूरी तरह से परहेज, मैं पूरी तरह से, जैसा कि आप सुझाव देते हैं, निश्चित रूप से सबसे सुरक्षित शर्त की तरह लगता है, लेकिन मैं sed vमौजूदा के लिए इसका उद्देश्य दिए गए उपयोग के साथ ठीक हूं ।
इवान एक्स

1
@lapo एक विकल्प एक फ़ंक्शन को परिभाषित करने के लिए है, मेरा संपादन देखें।
गाइल्स का SO- बुराई पर रोक '12

10

यदि आपको sedअच्छा खेलने के लिए कोई चाल नहीं मिलती है , तो आप कोशिश कर सकते हैं:

  1. उपयोग न करें -i:

    sed '1s/^/<!DOCTYPE html> \n/' "${file_name.html}" > "${file_name.html}.tmp" &&
      mv "${file_name.html}.tmp" "${file_name.html}"
    
  2. पर्ल का उपयोग करें

    perl -i -pe 'print "<!DOCTYPE html> \n" if $.==1;' "${file_name.html}"

8

ईडी

आप हमेशा edकिसी मौजूदा फ़ाइल के लिए एक लाइन प्रस्तुत करने के लिए उपयोग कर सकते हैं ।

$ printf '0a\n<!DOCTYPE html>\n.\nw\n' | ed my.html

विवरण

आस-पास के बिट्स उस निर्देश को फ़ाइल में जोड़ने के <!DOCTYPE html>लिए edनिर्देश देते हैं my.html

sed

मेरा मानना ​​है कि इस कमांड का sedउपयोग भी किया जा सकता है:

$ sed -i '1i<!DOCTYPE html>\n` testfile.csv

मैंने अंततः पर्ल का सहारा लिया, लेकिन एड का उपयोग करना एक अच्छा विकल्प है जो यूनिक्स जैसे उपयोगकर्ताओं के बीच लोकप्रिय नहीं है जैसा कि यह होना चाहिए।
लाल

@Red - सुनकर आपको समस्या हल हो गई। हाँ, मैंने नहीं देखा था कि पहले एक, googling ने इसे बदल दिया था और यह वास्तव में ऐसा करने के लिए सबसे पोर्टेबल, उपयुक्त तरीका लग रहा था।
SLM

7

आप मैन्युअल रूप perl -iसे हुड के तहत क्या करते हैं :

{ rm -f file && { echo '<!DOCTYPE html>'; cat; } > file;} < file

जैसे perl -i, कोई बैकअप नहीं है, और यहां दिए गए अधिकांश समाधानों की तरह, सावधान रहें कि यह अनुमतियों, फ़ाइल के स्वामित्व को प्रभावित कर सकता है और एक सिम्लिंक को नियमित फ़ाइल में बदल सकता है।

साथ में:

sed '1i\
<!DOCTYPE html>' file 1<> file

sedफ़ाइल को अपने आप से अधिलेखित कर देगा, इसलिए स्वामित्व और अनुमतियाँ या सहानुभूति को प्रभावित नहीं करेगा। यह GNU के साथ काम करता है sedक्योंकि sedआम तौर पर कमांड के fileसाथ इसे ओवरराइट करने से पहले (मेरे मामले में 4k) से डेटा से भरा एक बफर पढ़ा होगा i। यदि फ़ाइल 4k से अधिक है तो इस तथ्य को छोड़कर काम नहीं करेगा कि sedइसका आउटपुट भी बफ़र करता है।

मूल रूप से sedपढ़ने और लिखने के लिए 4k के ब्लॉक पर काम करता है। यदि सम्मिलित करने के लिए लाइन 4k से छोटी है, तो sedउस ब्लॉक को कभी भी अधिलेखित नहीं करेगा जो अभी तक पढ़ा नहीं है।

मैं हालांकि इस पर भरोसा नहीं करेगा।


echo '<!DOCTYPE html>'"" उद्धरण के बिना होना चाहिए या बच जाना चाहिए ।

@ अच्छा बिंदु। मैं उस बग के बारे में भूल जाता हूं
स्टीफन चेज़लस

यह यहाँ बहुत कम उत्तरों में से एक है जिसमें एक स्थिर, अनुमानित नाम के साथ "अस्थायी फ़ाइल" पर रीडायरेक्ट करने का एक विस्तृत खुला सुरक्षा छेद नहीं है यदि यह पहले से मौजूद है तो जाँच के बिना। मेरा मानना ​​है कि यह स्वीकृत उत्तर होना चाहिए। समूह कमांड के उपयोग का बहुत अच्छा प्रदर्शन, भी।
वाइल्डकार्ड

3

FreeBSD sed , जिसका उपयोग Mac OS X पर भी किया जाता है, को निम्न (regex) कमांड को सही और स्पष्ट रूप से परिभाषित करने और पहचानने के लिए स्विच के -eबाद विकल्प की आवश्यकता होती है -i

दूसरे शब्दों में, sed -i -e ...FreeBSD और GNU दोनों के साथ काम करना चाहिए sed

अधिक आम तौर पर, FreeBSD के बाद बैकअप एक्सटेंशन को छोड़ने से इसके कमांड-लाइन तर्कों को पार्स करते समय FreeBSD की ओर से भ्रम से बचने के लिए sed -iकुछ स्पष्ट sedविकल्प या स्विच की आवश्यकता होती है।-ised

(ध्यान दें, हालांकि, sedइन-प्लेस फ़ाइल संपादन फ़ाइल इनोड परिवर्तनों को जन्म देता है, "इन-प्लेस" फ़ाइलों का संपादन देखें )।

(एक सामान्य संकेत के रूप में, FreeBSD के हाल के संस्करण sedहै -rस्विच जीएनयू साथ संगतता बढ़ाने के लिए sed)।

echo a > testfile.txt
ls -li testfile.txt
#gsed -i -e 's/a/A/' testfile.txt
#bsdsed -i 's/a/A/' testfile.txt  # does not work
bsdsed -i -e 's/a/A/' testfile.txt
ls -li testfile.txt
cat testfile.txt

5
नहीं है, bsdsed -i -e 's/a/A/'है यथा-स्थान संपादन, यह एक "-e" प्रत्यय के साथ मूल की बचत के साथ संपादन है ( testfile.txt-e)।
स्टीफन चेज़लस

ध्यान दें कि GNU sed भी FreeBSD के साथ संगतता के लिए -E (-r के अलावा) का समर्थन करता है। -अगले POSIX संस्करण में निर्दिष्ट होने की संभावना है, इसलिए हम सभी को उस -r गैर-भावना के बारे में भूल जाना चाहिए और दिखावा करना चाहिए कि यह कभी अस्तित्व में नहीं था।
स्टीफन चेज़लस

2

sed -iजहां तक ​​संभव हो दौड़ की स्थितियों से बचने के लिए एक ही फाइल को पोर्ट्रेट तरीके से अनुकरण करने के लिए:

sed 'script' <<FILE >file
$(cat file)
FILE

वैसे, यह उस संभावित समस्या को भी संभालता sed -iहै, जो इसमें मौजूद है, निर्देशिका और फ़ाइल अनुमतियों के आधार पर, sed -iएक उपयोगकर्ता को एक फ़ाइल को अधिलेखित करने में सक्षम कर सकती है , जिसमें उपयोगकर्ता को संपादित करने की अनुमति नहीं है।

आप बैकअप भी कर सकते हैं जैसे:

sed 'script' <<FILE >file
$(tee file.old <file)
FILE

2

आप पूर्व मोड में विम का उपयोग कर सकते हैं:

ex -sc '1i|<!DOCTYPE html>' -cx file
  1. 1 पहली पंक्ति का चयन करें

  2. i टेक्स्ट और न्यूलाइन डालें

  3. x सहेजें और बंद करें

या यहां तक ​​कि, टिप्पणियों के रूप में, सादे पुराने मानक ex :

printf '%s\n' 1i '<!DOCTYPE html>' . x | ex file 

यहाँ कुछ भी विशिष्ट नहीं है। यह पूरी तरह से POSIX विनिर्देशों केex अनुरूप है , सिवाय इसके कि कार्यान्वयन को कई झंडे का समर्थन करने की आवश्यकता नहीं है-c । निश्चित पोर्टेबिलिटी के लिए मैं उपयोग करूंगाprintf '%s\n' 1i '<!DOCTYPE html>' . x | ex file
वाइल्डकार्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.