क्या सोलारिस में "sed -i" कमांड का कोई विकल्प है?


11

मुझे अपनी परियोजना में फाइल में कुछ मौजूदा पाठ को बदलने की आवश्यकता है जैसे fooकुछ अन्य पाठ के साथ fooofoo:

abc.txt
name
foo
foo1

इसलिए मैंने कोशिश की:

sed -i "s/foo/fooofoo/g" abc.txt

हालाँकि मुझे यह त्रुटि मिली:

sed: अवैध विकल्प - i

मैंने उस मैनुअल में पाया जिसका मुझे उपयोग करना है:

sed -i\ "s/foo/fooofoo/g" abc.txt

हालांकि यह भी काम नहीं कर रहा है।

मुझे इसमें perlऔर awkभी विकल्प मिले लेकिन सोलारिस में एक घोल की sedबहुत प्रशंसा होगी।

मैं इस संस्करण का उपयोग कर रहा हूँ bash:

GNU बैश, संस्करण 3.2.57 (1) -release (स्पार्क-सन-सोलारिस 2.10)


सोलारिस 11 और बाद में, बस /usr/gnu/bin/sed-आई समर्थन प्राप्त करने के लिए उपयोग करें।
alanc

जवाबों:


15

का उपयोग करें ed। यह अधिकांश प्लेटफार्मों पर उपलब्ध है और यह आपकी फ़ाइलों को इन-प्लेस कर सकता है।
चूंकि पैटर्न बदलने के लिए वाक्य रचना sedपर आधारित edहै, समान है:

ed -s infile <<\IN
,s/old/new/g
w
q
IN

edइसके बजाय exसिर्फ जिज्ञासु क्यों ? (मुझे पता है कि दोनों POSIX आज्ञाकारी हैं और मैं चश्मे से जुड़ा हुआ हूं।)))
वाइल्डकार्ड

1
@Wildcard - मैं विपरीत पूछ सकता है - क्यों ex? आपके प्रश्न का उत्तर देने के लिए: चूंकि मैं कभी उपयोग नहीं करता ex हूं इसलिए मैं इससे परिचित नहीं हूं। btw, मैंने देखा है कि सेटअप कहाँ edमौजूद exथा, लेकिन नहीं था (लेकिन इसके विपरीत नहीं) ... सबसे उल्लेखनीय मेरा लैपटॉप है :)
don_crissti

अच्छा उत्तर। :) मेरा जवाब: चूंकि मैं हर समय विम का उपयोग करता हूं, इसलिए मैं exआज्ञाओं से बहुत परिचित हूं । सभी viआदेशों को आप टाइप कर सकते हैं जो एक कोलोन के साथ शुरू होते हैं exकमांड। बेशक कुछ विम-विशिष्ट एक्सटेंशन हैं, लेकिन सिर्फ कमांड का मुख्य सेट अविश्वसनीय रूप से शक्तिशाली और लचीला है और स्क्रिप्टेड संपादन के लिए काफी है।
वाइल्डकार्ड

मेरा मंज़रो सिस्टम है exऔर अभी तक नहीं है ed
मध्य

8

यदि आप GNU सेड को स्थापित नहीं कर सकते हैं, तो उपयोग करें:

sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt

यह अस्थायी फ़ाइल में सेड का आउटपुट भेजने के लिए पुनर्निर्देशन का उपयोग करता है । यदि sed सफलतापूर्वक पूरा होता है, तो यह abc.txtअस्थायी फ़ाइल के साथ ओवरराइट करता है।

जैसा कि GNU sed के लिए स्रोत कोड से देखा जा सकता है , यह ठीक वैसा ही sed -iहै। तो, यह बस के बारे में के रूप में कुशल है sed -i

यदि एक मौका है जो abc.tmpपहले से मौजूद है, तो आप mktempअस्थायी के लिए अद्वितीय नाम उत्पन्न करने के लिए उपयोग करना चाहते हैं या एक समान उपयोगिता हो सकती है ।


मदद के लिए शुक्रिया। हालाँकि क्या सोलारिस में कोई विकल्प है जिसके द्वारा हम बिना किसी अस्थायी फ़ाइल को बनाए मौजूदा फ़ाइल को अपडेट कर सकते हैं?
tpsaitwal

10
आप इसे तोड़ने के लिए नफरत है, लेकिन यहां तक ​​कि sed एक अस्थायी फ़ाइल बनाता है। git.savannah.gnu.org/cgit/sed.git/tree/sed/sed.c#n84
जेफ स्कालर

1
आप इसे कर सकते हैं यदि आप हार्ड लिंक की परवाह नहीं करते हैं - मेरा उदाहरण देखें। अभी भी एक अस्थायी फ़ाइल है, लेकिन यह छिपा हुआ है (अनाम)। अस्थायी के बिना, आपको उपयोग करने की आवश्यकता होगी ed, क्योंकि यह पूरी फ़ाइल को मेमोरी में पढ़ता है।
टोबी स्पाइट

3

यदि आप के बराबर चाहते हैं sed -i.bak, यह बहुत आसान है।

GNU sed के लिए इस लिपि पर विचार करें:

#!/bin/sh

# Create an input file to demonstrate
trap 'rm -r "$dir"' EXIT
dir=$(mktemp -d)
grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo"

# sed program - removes 'aardvark' and 'aardvarks'
script='/aard/d'

##########
# What we want to do
sed -i.bak -e "$script" "$dir"
##########

# Prove that it worked
ls "$dir"
cat "$dir/foo"

हम बस चिह्नित लाइन को बदल सकते हैं

cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo"

यह मौजूदा फ़ाइल को एक बैकअप बनाता है, और एक नई फ़ाइल लिखता है।

अगर हम इसके बराबर चाहते हैं

sed -i -e "$script" "$dir"  # no backup

तो यह थोड़ा और अधिक जटिल है। हम मानक इनपुट के रूप में पढ़ने के लिए फ़ाइल खोल सकते हैं, फिर इसे बदलने के लिए sed के आउटपुट को निर्देशित करने से पहले इसे अनलिंक करें:

( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" )

हम इसे एक उप-शेल में करते हैं, ताकि इसके बाद भी हमारी मूल गति उपलब्ध हो। इनपुट को स्विच करना और बिना सबस्क्रिप्शन के वापस स्विच करना संभव है, लेकिन यह तरीका मुझे स्पष्ट लगता है।

ध्यान दें कि हम एक नई fooफ़ाइल बनाने के बजाय पहले कॉपी करने के लिए सावधान हैं - यह महत्वपूर्ण है अगर फ़ाइल एक से अधिक नामों से जानी जाती है (यानी इसमें हार्ड लिंक हैं) और आप सुनिश्चित करना चाहते हैं कि आप लिंक को न तोड़ें ।


3

सबसे पहले, आपको पता होना चाहिए कि i\आप जिस कमांड का उल्लेख कर रहे हैं, वह संपादित पाठ को फ़ाइल में सहेजने के लिए टेक्स्ट की एक पंक्ति सम्मिलित करने के लिए नहीं है। उसके लिए उपयोग करने का कोई POSIX- निर्दिष्ट तरीका नहीं sedहै।

क्या आप कर सकते हैं कर इस्तेमाल होता है ex, जो है POSIX द्वारा निर्दिष्ट :

printf '%s\n' '%s/find/replace/g' 'x' | ex file.txt

xआदेश के लिए है "बचाने के लिए और बाहर निकलने के।" आप भी उपयोग कर सकते हैं wqलेकिन xकम है।

%स्थानापन्न आदेश साधन के शुरू में हस्ताक्षर, "बफर में हर पंक्ति को यह आदेश लागू करें।" आप भी इस्तेमाल कर सकते हैं 1,$s/find/replace/g


के बीच एक बड़ा अंतर exहै और sedवह यह है कि sedएक है धारा संपादक। यह केवल क्रमिक रूप से संचालित होता है, लाइन से लाइन। exकी तुलना में कहीं अधिक लचीला है, और वास्तव में आप सीधे इंटरैक्टिव पाठ फ़ाइल संपादन कर सकते हैं ex। यह तत्काल पूर्ववर्ती है vi


1

अस्थायी फ़ाइल का उपयोग करना sedऔर न दिखाई देना :

आप एक अलग दृश्यमान "अस्थायी फ़ाइल" बनाने से बच सकते हैं :

exec 3<abc.txt
rm abc.txt
sed 's/foo/fooofoo/' <&3 >abc.txt
exec 3<&-

व्याख्या

यूनिक्स जैसी प्रणाली वास्तव में डिस्क से फ़ाइल की सामग्री को तब तक नहीं हटाती है जब तक कि यह फाइलसिस्टम में दोनों को अनलिंक नहीं करता है , और किसी भी प्रक्रिया में नहीं खुलता है। तो आप exec 3<फ़ाइल डिस्क्रिप्टर 3 पर पढ़ने के लिए शेल में फ़ाइल को खोलने के लिए कर सकते हैं , rmफ़ाइल (जो इसे फ़ाइल सिस्टम से अनलिंक करता है), और फिर sedइसके इनपुट के रूप में उपयोग की गई फ़ाइल डिस्क्रिप्टर 3 के साथ कॉल करें ।

ध्यान दें कि यह इससे बहुत अलग है:

# Does not work.
sed 's/foo/fooofoo/' <abc.txt >abc.txt

अंतर यह है कि जब आप इसे एक कमांड में करते हैं, तो शेल सिर्फ पढ़ने के लिए दोनों के लिए एक ही फाइल खोलता है, और फाइल को ट्रंक करने के विकल्प के साथ लिखने के लिए - चूंकि यह अभी भी एक ही फाइल है, इसलिए आप सामग्री खो देते हैं। लेकिन अगर आप इसे पढ़ने के लिए खोलते हैं, तो rmइसे, फिर लिखने के लिए एक ही पाथनाम खोलें, आप वास्तव में एक ही पथनाम पर एक नई फ़ाइल बना रहे हैं (लेकिन नए इनोड और डिस्क स्थान पर, क्योंकि मूल अभी भी खुला है): सामग्री अभी भी उपलब्ध हैं।

फिर एक बार जब आप कर लेते हैं, तो आप पहले खोले गए फ़ाइल डिस्क्रिप्टर को बंद कर सकते हैं (जो कि exec 3<&-विशेष सिंटैक्स करता है), जो मूल फ़ाइल को रिलीज़ करता है ताकि ऑपरेटिंग सिस्टम (डिस्क के रूप में चिह्नित) को हटा सके।

चेतावनियां

इस समाधान के बारे में ध्यान रखने योग्य कुछ बातें हैं:।

  1. आप केवल सामग्री के माध्यम से एक "गो" प्राप्त करते हैं - फ़ाइल डिस्क्रिप्टर में "शेल" बैक के लिए कोई पोर्टेबल तरीका नहीं है - इसलिए एक बार जब कोई प्रोग्राम कुछ सामग्री पढ़ता है, तो अन्य प्रोग्राम केवल फ़ाइल के शेष को देखेंगे। और sedपूरी फाइल को पढ़ेगा।

  2. यदि आपके शेल / स्क्रिप्ट / सेड की मृत्यु हो जाती है, तो आपके ओरिजनल फाइल के गुम होने की बहुत कम संभावना है।


स्पष्ट होने के लिए, @TobySpeight ने पहले ही अपने जवाब के अंत में इस समाधान का एक उदाहरण पोस्ट किया था, लेकिन मुझे लगा कि यह अधिक गहराई से विस्तार का उपयोग कर सकता है।
mtraceur

Downvoter करने के लिए: जबकि मुझे यकीन है कि सिर्फ एक downvote छोड़ने से आपको अपने बारे में अच्छा महसूस होता है, मैं इस बात की सराहना करता हूं कि अगर आप इस जवाब के साथ आपके पास क्या मुद्दे हैं, तो यह कैसे सुधार कर सकता है, आदि के रूप में प्रतिक्रिया प्रदान करके अधिक योगदान देगा। ।
mtraceur

हो सकता है कि आप perl -i
c4f4t0r

@ c4f4t0r: देर से जवाब के लिए क्षमा करें: हाँ, perl -iएक और अच्छा विकल्प है। प्रश्न ने विशेष रूप से सोलारिस के साथ संगत समाधान का अनुरोध किया sed, इसके समाधान के विपरीत perlऔर awkजिसका उन्होंने पहले से ही उल्लेख किया था। इसके अलावा, मेरा जवाब मुख्य रूप से कुछ ऐसा जोड़ना था जो मुझे लगा कि किसी भी अन्य उत्तर से जानना और गायब होना उपयोगी है।
mtraceur
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.