इन-प्लेस परिवर्तनों में "sed" की रिपोर्ट कैसे करें


23

sedस्ट्रिंग्स को इन-प्लेस में बदलने के लिए उपयोग करते समय, क्या यह उन परिवर्तनों की रिपोर्ट करने का एक तरीका है जो यह करता है (पुरानी और नई फ़ाइलों के अंतर पर निर्भर किए बिना)?

उदाहरण के लिए, मैं कमांड लाइन कैसे बदल सकता हूं

find . -type f | xargs sed -i 's/abc/def/g'

इसलिए मैं मक्खी पर किए गए परिवर्तनों को देख सकता हूं?

जवाबों:


15

आप इस्तेमाल कर सकते हैं sedकी wकिसी के साथ झंडा /dev/stderr, /dev/tty, /dev/fd/2आपके सिस्टम पर समर्थित है। जैसे इनपुट के fileसाथ:

foo first
second: missing
third: foo
none here

चल रहा है

sed -i '/foo/{
s//bar/g
w /dev/stdout
}' file

आउटपुट:

bar first
third: bar

हालांकि fileसामग्री को बदल दिया गया था:

bar first
second: missing
third: bar
none here

तो आपके मामले में, चल रहा है:

find . -type f -printf '\n%p:\n' -exec sed -i '/foo/{
s//bar/g
w /dev/fd/2
}' {} \;

फ़ाइलों को जगह और आउटपुट में संपादित करेगा:

./file1:
बार सामान
अधिक बार

./file2:

./file3:
पहले बार
तीसरा: बार

आप original line >>> modified lineजैसे कुछ प्रिंट भी कर सकते हैं :

find . -type f -printf '\n%p:\n' -exec sed -i '/foo/{
h
s//bar/g
H
x
s/\n/ >>> /
w /dev/fd/2
x
}' {} \;

फ़ाइलों को स्थान और आउटपुट में संपादित करता है:

./file1:
फू सामान >>> बार सामान
अधिक foo >>> अधिक बार

./file2:

./file3:
फू पहले >>> बार पहले
तीसरा: फू >>> तीसरा: बार

16

आप इसे pपहले पास पर रिंट एक्शन का उपयोग करके दो पास में कर सकते हैं :

find . -type f | xargs sed --quiet 's/abc/def/gp'

जहाँ --quietsed हर लाइन को नहीं दिखाता है और pप्रत्यय केवल उन लाइनों को दिखाता है जहाँ प्रतिस्थापन से मेल खाता है।

यह सीमा है कि sed नहीं दिखाएगा कि कौन सी फाइलें बदल रही हैं जो निश्चित रूप से कुछ अतिरिक्त जटिलता के साथ तय की जा सकती हैं।


यह काफी कुछ नहीं करता है जो मुझे चाहिए था क्योंकि आपको दो पास की आवश्यकता थी, लेकिन मैं मतदान कर रहा हूं क्योंकि मैंने अभी इस पी चीज़ को सीखा है और यह बहुत उपयोगी है। विशेष रूप से अगर, जैसा कि आपने कहा, फाइलें भी छपी थीं। कुछ इस तरहfor x in `find . -type f`; do echo ///File $x: ; sed --quiet 's/abc/def/gp' $x; done
ऋक

@ मेरे पास कई sedअभिव्यक्ति हैं, मैं /gpहर एक के लिए लिखना नहीं चाहता । इसे कैसे स्थापित किया जाए?
अल्हलाल

8

मुझे नहीं लगता कि यह संभव है, लेकिन इसके बजाय पर्ल का उपयोग करने के लिए वर्कअराउंड हो सकता है:

find . -type f | xargs perl -i -ne 's/abc/def/ && print STDERR' 

यह मानक त्रुटि के लिए परिवर्तित लाइनों को प्रिंट करेगा । उदाहरण के लिए:

$ cat foo
fooabcbar
$ find . -type f | xargs perl -i -ne 's/abc/def/ && print STDERR' 
foodefbar

आप इसे थोड़ा और जटिल बना सकते हैं, लाइन नंबर, फ़ाइल का नाम, मूल लाइन और परिवर्तित लाइन प्रिंट कर सकते हैं:

$ find . -type f | 
   xargs perl -i -ne '$was=$_; chomp($was);
                      s/abc/def/ && print STDERR "$ARGV($.): $was : $_"' 
./foo(1): fooabcbar : foodefbar

+1 आप $ARGVउस फ़ाइल के नाम के लिए भी उपयोग कर सकते हैं जिस पर काम किया जा रहा है।
जोसफ आर।

@JosephR। अच्छी बात है, जोड़ा गया।
terdon

धन्यवाद, यह शायद मददगार है (यह खुद का परीक्षण नहीं किया है)। मैं चयन नहीं कर रहा हूँ क्योंकि यह sed का उपयोग नहीं करता है, इसलिए यह प्रश्न का उत्तर नहीं देता है।
रिकाब

@ricab है कि ठीक है, तो आप एक जवाब स्वीकार नहीं करना चाहिए जब तक कि यह वास्तव में उत्तर देता है आपके सवाल का। हालांकि इस तरह की सरल चीजों के लिए ध्यान रखें, perl'वाक्यविन्यास बहुत समान है sedऔर मुझे नहीं लगता कि आप जो पूछ रहे हैं वह वास्तव में आपके साथ है sed
terdon

3

यह w ध्वज का उपयोग करना संभव है जो एक फ़ाइल में वर्तमान पैटर्न लिखता है। इसलिए इसे स्थानापन्न कमांड में जोड़कर हम एक फ़ाइल के लिए लगातार प्रतिस्थापन की रिपोर्ट कर सकते हैं और नौकरी समाप्त होने के बाद इसे प्रिंट कर सकते हैं। मुझे grep के साथ बदले हुए स्ट्रिंग को भी रंगना पसंद है।

sed -i -e "s/From/To/gw /tmp/sed.done" file_name
grep --color -e "To" /tmp/sed.done

ध्यान दें, कि w और उसके फ़ाइल नाम के बीच केवल एक स्थान होना चाहिए ।

यह अंतर से भी बेहतर है, क्योंकि अलग-अलग भी बदलाव दिखा सकते हैं, भले ही वे sed द्वारा नहीं किए गए हों।


बस इसका परीक्षण किया है और sed केवल वह पंक्तियाँ लिखता है जो इसके लिए प्रतिस्थापित है sed.done। मूल फ़ाइल में "टू" वाली लाइनें इसलिए मुद्रित नहीं की जाती हैं sed.done, इस प्रकार जब आप grep "To" sed.doneकेवल उन पंक्तियों को देखेंगे जिन्हें बदल दिया जाता है sed। फ़ाइल में मूल पंक्ति आपको दिखाई नहीं देगी, इससे पहले कि आप इसे अपना लक्ष्य बना रहे हैं ...
aairey

1

मुझे @terdon समाधान पसंद है - पर्ल इसके लिए अच्छा है।

यहाँ मेरा दिया संस्करण है कि:

  • उन फ़ाइलों को बदलने की कोशिश नहीं करेंगे जिनमें मिलान स्ट्रिंग नहीं है
  • बदलने वाले फ़ाइलों के पहले संस्करण का बैकअप लेंगे (.bak संस्करण बनाएँ)
  • प्रत्येक फ़ाइल / लिनेनो को बदल देगा, और आसान पढ़ने के लिए उस लाइन के ओएलडी और नए संस्करणों को दिखाएगा

कोड

find /tmp/test -type f ! -name "*.bak" -exec grep -l '/opt/gridmon' {} \; | xargs -L1 perl -ni'.bak' -e'$old=$_; s/\/opt\/gridmon/~/g && print STDERR "$ARGV($.):\n\tOLD:$old\tNEW:$_"'

उदाहरण आउटपुट

/tmp/test/test4.cfg(13):
    OLD:    ENVFILE /opt/gridmon/server/etc/gridmonserver.cfg
    NEW:    ENVFILE ~/server/etc/gridmonserver.cfg
/tmp/test/test4.cfg(24):
    OLD:    ENVFILE /opt/gridmon/server/etc/gridmonserver.cfg
    NEW:    ENVFILE ~/server/etc/gridmonserver.cfg
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.