कमांड लाइन पर regex बैकस्लैश से बचने के लिए आवश्यक बैकस्लैश की संख्या


12

मुझे हाल ही में कमांड-लाइन पर कुछ रेगेक्स से परेशानी हुई, और पाया कि बैकस्लैश के मिलान के लिए, विभिन्न अक्षरों का उपयोग किया जा सकता है। यह संख्या regex (कोई नहीं, एकल उद्धरण, दोहरे उद्धरण) के लिए उपयोग किए जाने वाले उद्धरण पर निर्भर करती है। मेरे मतलब के लिए निम्नलिखित बैश सत्र देखें:

echo "#ab\\cd" > file
grep -E ab\cd file
grep -E ab\\cd file
grep -E ab\\\cd file
grep -E ab\\\\cd file
#ab\cd
grep -E ab\\\\\cd file
#ab\cd
grep -E ab\\\\\\cd file
#ab\cd
grep -E ab\\\\\\\cd file
#ab\cd
grep -E ab\\\\\\\\cd file
grep -E "ab\cd" file
grep -E "ab\\cd" file
grep -E "ab\\\cd" file
#ab\cd
grep -E "ab\\\\cd" file
#ab\cd
grep -E "ab\\\\\cd" file
#ab\cd
grep -E "ab\\\\\\cd" file
#ab\cd
grep -E "ab\\\\\\\cd" file
grep -E 'ab\cd' file
grep -E 'ab\\cd' file
#ab\cd
grep -E 'ab\\\cd' file
#ab\cd
grep -E 'ab\\\\cd' file

इस का मतलब है कि:

  • बिना उद्धरण के, मैं 4-7 वास्तविक बैकस्लैश के साथ एक बैकस्लैश का मिलान कर सकता हूं
  • दोहरे उद्धरण चिह्नों के साथ, मैं 3-6 वास्तविक बैकस्लैश के साथ एक बैकस्लैश मिलान कर सकता हूं
  • सिंगल कोट्स के साथ, मैं 2-3 वास्तविक बैकस्लैश के साथ एक बैकस्लैश का मिलान कर सकता हूं

मैं समझता हूं कि एक अतिरिक्त बैकस्लैश को शेल (बैश मैन पेज से) द्वारा अनदेखा किया जाता है:

"एक गैर-उद्धृत बैकस्लैश (\) एस्केप कैरेक्टर है। यह अगले साल के शाब्दिक मूल्य को सुरक्षित रखता है"

यह एकल-उद्धृत उदाहरणों पर लागू नहीं होता है, क्योंकि एकल उद्धरणों में कोई पलायन नहीं किया जाता है।

और एक अतिरिक्त बैकस्लैश को grep कमांड द्वारा अनदेखा किया जाता है ("\ c" सिर्फ "c" बच जाता है, लेकिन यह "c" के समान ही है, क्योंकि "c" का regex में विशेष अर्थ नहीं है)।

यह एकल उद्धरणों के साथ उदाहरण के व्यवहार की व्याख्या करता है, लेकिन मैं वास्तव में अन्य दो उदाहरणों को नहीं समझता हूं, खासकर इसलिए कि गैर-कोटेड डबल-उद्धृत स्ट्रिंग्स के बीच अंतर है।

फिर, बैश मैन पेज से एक उद्धरण:

"दोहरे उद्धरणों में वर्णों को जोड़ना, उद्धरणों के भीतर सभी वर्णों के शाब्दिक मूल्य को, $,`, \ _ और, के अपवाद के साथ सुरक्षित रखता है, जब इतिहास विस्तार सक्षम होता है; "।

मैंने awk /ab\cd/{print} fileएक ही परिणाम के साथ GNU awk (जैसे ) के साथ एक ही कोशिश की ।

हालाँकि, पर्ल अलग परिणाम दिखाता है (उदाहरण के लिए perl -ne "/ab\\cd/"\&\&print file):

  • कोई उद्धरण के साथ, मैं 4-5 वास्तविक बैकस्लैश के साथ एक बैकस्लैश का मिलान कर सकता हूं
  • दोहरे उद्धरण चिह्नों के साथ, मैं 3-4 वास्तविक बैकस्लैश के साथ एक बैकस्लैश का मिलान कर सकता हूं
  • सिंगल कोट्स के साथ, मैं 2 वास्तविक बैकस्लैश के साथ एक बैकस्लैश का मिलान कर सकता हूं

क्या कोई समझा सकता है कि grep और awk के लिए कमांड-लाइन पर गैर-उद्धृत और डबल-qouted regex तार के बीच अंतर? मैं पर्ल के व्यवहार के स्पष्टीकरण में दिलचस्पी नहीं रखता, क्योंकि मैं आमतौर पर पर्ल वन-लाइनर्स का उपयोग नहीं करता हूं।

जवाबों:


10

निर्विवाद उदाहरण के लिए, प्रत्येक \\जोड़ी एक बैकस्लैश को grep में पास करती है, इसलिए 4 बैकस्लैश दो grep को पास करते हैं, जो एकल बैकस्लैश में बदल जाता है। 6 बैकस्लैश तीन grep से गुजरते हैं, एक बैकलैश और एक के लिए अनुवाद करते हैं \c, जो कि बराबर है c। एक अतिरिक्त बैकलैश कुछ भी नहीं बदलता है, क्योंकि यह शेल द्वारा अनुवादित है \c-> c। खोल में आठ बैकस्लैश चार grep में हैं, दो में अनुवादित हैं, इसलिए यह अब मेल नहीं खाता है।

दोहरे उद्धरण चिह्नों में उदाहरण के लिए, नोट करें जो बैश मैनपेज से आपके दूसरे उद्धरण का अनुसरण करता है:

बैकस्लैश अपने विशेष अर्थ को केवल तभी रखता है जब निम्न में से किसी एक अक्षर का अनुसरण किया जाता है: $, `,”, \, या newline।

यानी जब आप एक विषम संख्या में बैकस्लैश देते हैं, तो अनुक्रम समाप्त हो जाता है \c, जो cकि अनछुए मामले में बराबर होगा , लेकिन जब उद्धृत किया जाता है, तो बैकस्लैश अपना विशेष अर्थ खो देता है, इसलिए \cgrep को पास कर दिया जाता है। यही कारण है कि "संभव" बैकस्लैश की श्रेणी (यानी जो आपके उदाहरण फ़ाइल से मेल खाते पैटर्न बनाते हैं) एक-एक करके नीचे स्लाइड करते हैं।


... और फिर कुछ विषमताएँ हैं: उदाहरण के लिए: printf "\ntest""परीक्षण" से पहले एक नई पंक्ति सम्मिलित करेंगे, भले ही इसे शेल द्वारा "\n"अनुवादित किया जाना चाहिए "n"क्योंकि यह डबल उद्धरण है ... (इसलिए अपेक्षित परिणाम होना चाहिए, के लिए) "एनटेस्ट", "नेस्टेस्ट"। हमें लिखने की आदत डालनी चाहिए: printf "\\ntest"या printf '\ntest', लेकिन किसी तरह मुझे इसके बजाय विषमता पर भरोसा करने वाली बहुत सारी स्क्रिप्ट दिखाई देती है।
ओलिवियर दुलक

6

इस लिंक ने बैश कोट्स और एस्केपिंग का वर्णन किया है

आपका प्रश्न पहले तीन खंडों से संबंधित है।

  • प्रति चरित्र भागने
  • कमजोर उद्धरण "दोहरे उद्धरण"
  • मजबूत उद्धरण 'एकल उद्धरण'
  • ANSI C स्ट्रिंग उद्धरण की तरह
  • I18N / L10N उद्धृत (अंतर्राष्ट्रीयकरण और स्थानीयकरण)

नीचे एक चार्ट दिया गया है कि कैसे स्ट्रिंग्स bashउन पर गुजरती है grepऔर grepआंतरिक रूप से उन्हें आगे कैसे व्याख्या करती है।

चलो पहले देखो echo "#ab\\cd" > file
में कमजोर उद्धृत ( "") "#ab\\cd", \\एक भाग निकले है \जो करने के लिए पारित हो जाता है fileएक भी शाब्दिक रूप में \। तो, fileशामिल है ab\cd

अब, आपके आदेशों के लिए: नीचे दिए गए चार्ट से यह देखने में मदद मिल सकती है कि प्रत्येक कॉल के साथ वास्तविक क्या होता है। *लोगों को जो फ़ाइल सामग्री से मेल खाते को दर्शाता है। यह वास्तव में बस के भागने के नियमों को लागू करने का मामला है, जैसा कि वेब पेज पर है, विशेष रूप से daniel kullmann`s जवाब पर ध्यान दें जहां वह एक कमजोर-उद्धृत स्थिति में व्यवहार से बचने के लिए संदर्भित करता है।

बैकस्लैश अपने विशेष अर्थ को केवल तभी रखता है जब निम्न में से किसी एक अक्षर का अनुसरण किया जाता है: $, `,”, \, या newline।


                            bash passes    grep further
                            to grep        resolves to         
grep -E ab\cd file            abcd           abcd   
grep -E ab\\cd file           ab\cd          abcd  
grep -E ab\\\cd file          ab\cd          abcd
grep -E ab\\\\cd file         ab\\cd         ab\cd    * 
grep -E ab\\\\\cd file        ab\\\cd        ab\cd    *
grep -E ab\\\\\\cd file       ab\\\cd        ab\cd    *    
grep -E ab\\\\\\\cd file      ab\\\cd        ab\cd    *
grep -E ab\\\\\\\\cd file     ab\\\\cd       ab\\cd

grep -E "ab\cd" file          ab\cd          abcd
grep -E "ab\\cd" file         ab\cd          abcd
grep -E "ab\\\cd" file        ab\\cd         ab\cd    *
grep -E "ab\\\\cd" file       ab\\cd         ab\cd    *
grep -E "ab\\\\\cd" file      ab\\\cd        ab\cd    *
grep -E "ab\\\\\\cd" file     ab\\\cd        ab\cd    *
grep -E "ab\\\\\\\cd" file    ab\\\\cd       ab\\cd    

grep -E 'ab\cd' file          ab\cd          abcd  
grep -E 'ab\\cd' file         ab\\cd         ab\cd    *
grep -E 'ab\\\cd' file        ab\\\cd        ab\cd    *
grep -E 'ab\\\\cd' file       ab\\\\cd       ab\\cd
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.