यह सुनिश्चित करने के लिए कि स्ट्रिंग को `sed` प्रतिस्थापन में प्रक्षेपित किया गया है सभी मेटाचर्स से बच जाता है


21

मेरे पास एक स्क्रिप्ट है जो एक पाठ स्ट्रीम पढ़ता है और एक सीड कमांड की एक फाइल बनाता है जिसे बाद में चलाया जाता है sed -f। उत्पन्न sed कमांड इस तरह हैं:

s/cid:image002\.gif@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1922/g
s/cid:image003\.gif@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1923/g
s/cid:image004\.jpg@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1924/g

स्क्रिप्ट जो sedआदेश उत्पन्न करता है मान लीजिए कुछ इस तरह है:

while read cid fileid
do
    cidpat="$(echo $cid | sed -e s/\\./\\\\./g)"
    echo 's/'"$cidpat"'/https:\/\/mysite.com\/files\/'"$fileid"'/g' >> sedscr
done

cidस्ट्रिंग में सभी रेगेक्स मेटाचैकर को सुनिश्चित करने और ठीक से प्रक्षेपित करने के लिए मैं स्क्रिप्ट में सुधार कैसे कर सकता हूं ?

जवाबों:


24

(यहां और क्रमशः) एक sकमांड के बाएं हाथ की ओर और दाहिने हाथ की तरफ इस्तेमाल किए जाने वाले चर से बचने के लिए , आप यह करेंगे:sed$lhs$rhs

escaped_lhs=$(printf '%s\n' "$lhs" | sed 's:[][\/.^$*]:\\&:g')
escaped_rhs=$(printf '%s\n' "$rhs" | sed 's:[\/&]:\\&:g;$!s/$/\\/')

sed "s/$escaped_lhs/$escaped_rhs/"

ध्यान दें कि $lhsएक नया वर्ण नहीं हो सकता है।

यही है, एलएचएस पर, सभी regexp ऑपरेटरों ( ][.^$*), भागने वाले चरित्र ( \), और विभाजक ( /) से बचें ।

RHS पर, आपको केवल &विभाजक, बैकस्लैश और न्यूलाइन वर्ण से बचने की आवश्यकता होती है (जो आप पिछले एक ( $!s/$/\\/) को छोड़कर प्रत्येक पंक्ति के अंत में बैकस्लैश सम्मिलित करके करते हैं ।

यही कारण है कि आप का उपयोग हो जाती है /अपने में एक विभाजक के रूप में sed sआदेश और के लिए सक्षम नहीं है कि विस्तारित आर ई के साथ -r(जीएनयू sed/ ssed/ ast/ busybox sed) या -E(BSDs, ast, हाल ही में जीएनयू, हाल ही में बिजीबॉक्स) या PCREs साथ -R( ssed) या संवर्धित आर ई के साथ -A/ -X( ast) जो सभी में अतिरिक्त आरई ऑपरेटर हैं।

मनमाने डेटा के साथ काम करते समय कुछ जमीनी नियम:

  • उपयोग न करें echo
  • अपने चर को उद्धृत करें
  • लोकेल के प्रभाव पर विचार करें (विशेष रूप से इसका चरित्र सेट: यह महत्वपूर्ण है कि बचने के sed कमांड उसी लोकेल में चलाए जाते हैं, जो sedकमांड में फरार स्ट्रिंग्स (और उसी sedकमांड के साथ) उदाहरण के लिए उपयोग होता है)
  • न्यूलाइन कैरेक्टर के बारे में मत भूलना (यहां आप जांचना चाहते हैं कि क्या $lhsकोई है और कार्रवाई करें)।

एक अन्य विकल्प यह है कि perlइसके बजाय sedपर्यावरण में स्ट्रिंग्स को पास करें और स्ट्रिंग्स को लेने के लिए \Q/ \E perlregexp ऑपरेटर्स का उपयोग करें :

A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'

perl(डिफ़ॉल्ट रूप से), लोकेल के कैरेक्टर सेट से प्रभावित नहीं होगा, जैसा कि उपरोक्त में, यह केवल स्ट्रिंग को बाइट्स के सरणियों के रूप में मानता है, जो कि कैरेक्टर (यदि कोई हो) के बारे में परवाह किए बिना वे उपयोगकर्ता के लिए प्रतिनिधित्व कर सकते हैं। साथ sed, आप करने के लिए स्थान तय करके एक ही प्राप्त कर सकते थे Cके साथ LC_ALL=Cसभी के लिए sedआदेश (हालांकि वह भी यदि कोई हो, त्रुटि संदेशों में से भाषा को प्रभावित करेगा)।


क्या होगा अगर मुझे दोहरे उद्धरण चिह्नों से बचने की आवश्यकता है?
मेनन

@ मेनन, दोहरे उद्धरण विशेष नहीं हैं sed, आपको उनसे बचने की आवश्यकता नहीं है।
स्टीफन चेज़लस

यह वाइल्डकार्ड का उपयोग करके पैटर्न मिलान के लिए इस्तेमाल नहीं किया जा सकता है, क्या यह कर सकता है?
मेनन

@Menon, नहीं, वाइल्डकार्ड पैटर्न मिलान के find's -nameनियमित अभिव्यक्ति से अलग है। वहाँ आपको केवल भागने की जरूरत है ?, *[
बैकलैश
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.