sed: अगर लाइन मिल जाए या फाइल न मिले तो फ़ाइल को समाप्त करने की अपील कैसे करें?


34

एकल इनपुट फ़ाइल के साथ जिसमें केवल टिप्पणियां (# के साथ शुरू) और VARIABLE = मान रेखाएं होती हैं, क्या एकल चर के लिए मान को बदलना संभव है यदि पाया गया और, अन्यथा, फ़ाइल नहीं होने पर जोड़ी को फ़ाइल के अंत में संलग्न करें?

मेरी वर्तमान विधि इसे पहले पास में हटाकर काम करती है, फिर इसे दूसरे पास में फ़ाइल के अंत में जोड़ देती है, लेकिन यह विधि लाइन ऑर्डर को गड़बड़ कर देती है (और यह दो अलग-अलग कमांड भी है):

sed -r "/^FOOBAR=.*$/d"      -i samefile &&
sed -r "$ a\FOOBAR=newvalue" -i samefile

वहाँ वैसे भी यह करने के लिए है, यानी। एक एकल सीड लाइन में लाइन ऑर्डर रखते हुए? अगर कुछ अन्य उपयोगिता (awk, ...) ऐसा करती है, तो मैं इसे सेड पर ले जाऊंगा।

जवाबों:


29

यह वास्तव में इसके साथ काफी सरल है sed: यदि कोई रेखा बस hपुराने स्थान पर sप्रतिलिपि बनाती है तो मान को सर्वव्यापी कर देती है।
ला $टी लाइन ई xचेंज होल्ड स्पेस और पैटर्न स्पेस पर फिर जांचें कि क्या बाद वाला खाली है। यदि यह खाली नहीं है, तो इसका मतलब है कि प्रतिस्थापन पहले से ही किया गया था इसलिए कुछ नहीं करना है। यदि यह खाली है, तो इसका मतलब है कि कोई भी मैच नहीं मिला है, इसलिए वांछित चर = मान के साथ पैटर्न स्पेस को प्रतिस्थापित करें और फिर होल्ड बफ़र में वर्तमान लाइन पर जाएं। अंत में, ई xफिर से बदलें:

sed '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile

ऊपर gnu sedवाक्य रचना है। पोर्टेबल:

sed '/^FOOBAR=/{
h
s/=.*/=newvalue/
}
${
x
/^$/{
s//FOOBAR=newvalue/
H
}
x
}' infile

1
अगर newvalueयह एक चर में संग्रहीत किया जाता है तो यह कैसा लगेगा ?
user1810087

sed "/^${varName}=/{h;s/=.*/=${varValue}/};\${x;/^$/{s//${varName}=${varValue}/;H};x}" ${VARFILE}चर के साथ, चर प्रतिस्थापन के लिए अनुमति देने के लिए दोहरे उद्धरण और $उस से बचना इस बिंदु पर प्रतिस्थापन नहीं है, इसके अतिरिक्त यदि आप मूल्य में संग्रहीत हैं $$varName:sed "/^${varName}=/{h;s/=.*/=${!varName}/};\${x;/^$/{s//${varName}=${!varName}/;H};x}" ${VARFILE}
DarkMukke

1
यह समाधान 'सरल' लोल नहीं है। लेकिन यह काम करता है। sed मैन पेज सबसे आसान चीजें नहीं हैं, जिससे आप आसानी से मदद कर सकते हैं, अगर आप अभिव्यक्ति के हर सेक्शन के प्रभाव का विस्तार कर सकते हैं :)
user2066480

18

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

grep -q "^FOOBAR=" file && sed "s/^FOOBAR=.*/FOOBAR=newvalue/" -i file || 
    sed "$ a\FOOBAR=newvalue" -i file

13

यहाँ एक सरल sedतरीका है, क्योंकि मुझे sed hold spaceकाम करना आसान नहीं है । यदि आप सहज हैं hold space, तो don_crissti दृष्टिकोण का उपयोग करने से मौजूदा लाइन से कुछ भी संरक्षित करने का अतिरिक्त अवसर मिलता है, लेकिन यह आमतौर पर बहुत दुर्लभ है।

इस दृष्टिकोण में, आप केवल सभी को प्रिंट करते हैं लेकिन वह रेखा जिसे आप छोड़ना चाहते हैं और फिर अंत में, प्रतिस्थापन को जोड़ते हैं।

sed -n -e '/^FOOBAR=/!p' -e '$aFOOBAR=newvalue' infile

1
यह संस्करण बहुत अच्छा है यदि आप एक ऐसी फ़ाइल को अपडेट करने की योजना बनाते हैं जिसमें एक मौजूदा लेकिन पुराना मूल्य हो सकता है।
guillem

3

अन्य उत्तरों के आधार पर, यदि आप जो करना चाहते हैं, वह परिवर्तनशील मान को प्रतिस्थापित कर सकता है यदि वह चर फ़ाइल में मौजूद है और इसे फ़ाइल के अंत में संलग्न करें यदि यह नहीं है (जो कि आपकी पोस्ट की गई sedकमांड नहीं है), तो आप यह कोशिश कर सकता है:

perl -ne '$c=1 if s/^FOOBAR=.*$/FOOBAR=newvalue/;  
             print; 
             END{print "FOBAR=newvalue" unless $c==1}' file > tmpfile && 
mv tmpfile file

1

यह awk में थोड़ा आसान है, हालाँकि "इन एडिटिंग" स्वचालित नहीं है:

awk -v varname="FOOBAR" -v newval="newvalue" '
    BEGIN {FS = OFS = "="}
    $1 == varname {$2 = newval; found = 1}
    {print}
    END {if (! found) {print varname, newval}}
' file > tempfile &&
mv tempfile file

1

बस उपयोग करें grepऔर echoएक खाली रिकॉर्ड बनाने के लिए:

grep -q '^FOOBAR=' somefile || echo 'FOOBAR=VALUE' >> somefile
sed -i 's/FOOBAR=.*$/FOOBAR=VALUE/' somefile 

प्रत्येक पंक्ति त्रुटि कोड शून्य के साथ बच जाती है।


आप एक अतिरिक्त कमांड जोड़ते समय लाइन ऑर्डर खो देते हैं grepऔरecho
BlakBat

वास्तव में यदि आप फ़ाइल के अंत में नए आइटम सम्मिलित करते हैं, लेकिन यदि आप एक पुराने मूल्य को बदलते हैं तो ऑर्डर करते रहें।
MUY बेल्जियम 15

0

वास्तव में निम्नलिखित के साथ काम करता है: sed -i '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile उत्तर में चोसेन-आई गायब है।


3
यह वास्तव में एक टिप्पणी है और मूल प्रश्न का उत्तर नहीं है । किसी लेखक से स्पष्टीकरण मांगने या उसका स्पष्टीकरण देने के लिए, उनकी पोस्ट के नीचे एक टिप्पणी छोड़ दें - आप हमेशा अपने स्वयं के पोस्ट पर टिप्पणी कर सकते हैं, और एक बार आपके पास पर्याप्त प्रतिष्ठा होने पर आप किसी भी पोस्ट पर टिप्पणी कर पाएंगे । कृपया पढ़ें कि मुझे टिप्पणी करने के लिए 50 प्रतिष्ठा की आवश्यकता क्यों है? मैं इसके बजाय क्या कर सकता हूं?
DavidPostill

-1

यह मेरे साथ ठीक काम करता है

grep ^FOOBAR= my.file && perl -i -ple "s/^FOOBAR=.+/FOOBAR=newvalue/g" my.file || echo FOOBAR=newvalue >> my.file

2
यह जवाब बहुत मायनों में बुरा है! grepऔर echoऔर perlबजाय में सब कुछ करने की perl? इसके अलावा, फ़ाइल से लिखना ( >> my.file) क्या आप इसे ( grep my.file) से पढ़ रहे हैं ?
18
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.