क्या बैश पैरामीटर विस्तार में बैक रेफरेंस का समर्थन करता है?


15

मैं नाम के एक चर है descrजो एक स्ट्रिंग शामिल कर सकते हैं Blah: -> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Fooआदि मैं प्राप्त करना चाहते हैं -> r1-ae0-2, -> s7-Gi0-0-1:1-USस्ट्रिंग से भाग। फिलहाल मैं इसके लिए इस्तेमाल करता हूं descr=$(grep -oP '\->\s*\S+' <<< "$descr"। क्या ऐसा करने के लिए इससे अच्छा तरीका है? क्या पैरामीटर विस्तार के साथ ऐसा करना भी संभव है?

जवाबों:


20

ksh93और zshबैक-रेफरेंस (या अधिक सटीक 1 , प्रतिस्थापन में समूहों को कैप्चर करने के लिए संदर्भ) का समर्थन अंदर है ${var/pattern/replacement}, नहीं bash

ksh93:

$ var='Blah: -> r1-ae0-2 / [123]'
$ printf '%s\n' "${var/*@(->*([[:space:]])+([^[:space:]]))*/\1}"
-> r1-ae0-2

zsh:

$ var='Blah: -> r1-ae0-2 / [123]'
$ set -o extendedglob
$ printf '%s\n' "${var/(#b)*(->[[:space:]]#[^[:space:]]##)*/$match[1]}"
-> r1-ae0-2

( mkshमैन पेज में यह भी उल्लेख है कि भविष्य के संस्करण ${KSH_MATCH[1]}पहले कैप्चर ग्रुप के लिए इसका समर्थन करेंगे। 2017-04-25 तक उपलब्ध नहीं है)।

हालाँकि, bashआप कर सकते हैं:

$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] &&
  printf '%s\n' "${BASH_REMATCH[0]}"
-> r1-ae0-2

जो बेहतर है क्योंकि यह जांचता है कि पैटर्न पहले पाया गया है।

यदि आपके सिस्टम का regexps समर्थन \s/ करता है \S, तो आप यह भी कर सकते हैं:

re='->\s*\S+'
[[ $var =~ $re ]]

इसके साथ zsh, आप PCRE की पूरी शक्ति प्राप्त कर सकते हैं:

$ set -o rematchpcre
$ [[ $var =~ '->\s*\S+' ]] && printf '%s\n' $MATCH
-> r1-ae0-2

इसके साथ zsh -o extendedglob, यह भी देखें:

$ printf '%s\n' ${(SM)var##-\>[[:space:]]#[^[:space:]]##}
-> r1-ae0-2

portably:

$ expr " $var" : '.*\(->[[:space:]]*[^[:space:]]\{1,\}\)'
-> r1-ae0-2

यदि स्ट्रिंग में पैटर्न की कई घटनाएं होती हैं, तो उन सभी समाधानों के साथ व्यवहार अलग-अलग होगा। हालाँकि उनमें से कोई भी आपको अपने GNU- grepआधारित समाधान की तरह सभी मैचों की एक नई सूची से अलग नहीं देगा ।

ऐसा करने के लिए, आपको हाथ से लूपिंग करने की आवश्यकता होगी। उदाहरण के लिए, इसके साथ bash:

re='(->\s*\S+)(.*)'
while [[ $var =~ $re ]]; do
  printf '%s\n' "${BASH_REMATCH[1]}"
  var=${BASH_REMATCH[2]}
done

इसके साथ zsh, आप सभी मैचों को एक सरणी में संग्रहीत करने के लिए इस तरह की चाल का सहारा ले सकते हैं:

set -o extendedglob
matches=() n=0
: ${var//(#m)->[[:space:]]#[^[:space:]]##/${matches[++n]::=$MATCH}}
printf '%s\n' $matches

1 बैक-रेफरेंस आमतौर पर एक पैटर्न को निर्दिष्ट करता है जो एक पुराने समूह द्वारा मिलान किए गए संदर्भ को संदर्भित करता है। उदाहरण के लिए, \(.\)\1मूल नियमित अभिव्यक्ति एक ही चरित्र के बाद उसी चरित्र से मेल खाती है (यह मेल खाता है aa, पर नहीं ab)। यह उसी पैटर्न में \1उस \(.\)कैप्चर ग्रुप का बैक-रेफरेंस है ।

ksh93अपने प्रतिमानों में बैक-रेफरेंस का समर्थन करता है (उदाहरण के ls -d -- @(?)\1लिए फ़ाइल के नामों को सूचीबद्ध करेगा जिसमें दो समान अक्षर होते हैं), अन्य गोले नहीं। मानक BRE और PCRE बैक-रेफ़रेंस का समर्थन करते हैं लेकिन मानक ERE का नहीं, हालाँकि कुछ ERE कार्यान्वयन इसे विस्तार के रूप में समर्थन करते हैं। bash's [[ foo =~ re ]]का उपयोग करता है eres।

[[ aa =~ (.)\1 ]]

मेल नहीं खाएगा, लेकिन

re='(.)\1'; [[ aa =~ $re ]]

हो सकता है कि सिस्टम का ERE इसका समर्थन करता है।


9

आप पहले ␣->␣("तीर" सहित) और अंतिम के बाद ␣/(स्थान और स्लैश सहित ) सब कुछ हटाना चाहते हैं ।

string="Blah: -> r1-ae0-2 / [123]"
string=${string/*->/->}
string=${string/ \/*}

$stringअब हो जाएगा -> r1-ae0-2

वही दो प्रतिस्थापन में बदल -> s7-Gi0-0-1:1-US / Fooजाएगा -> s7-Gi0-0-1:1-US


3

यह निश्चित रूप से उत्तर देना असंभव है बिना सटीक स्वरूप को जाने हर संदेश। हालांकि, एक सामान्य दृष्टिकोण के रूप में आप कुछ विशिष्ट क्षेत्रों का उपयोग करके प्रिंट कर सकते हैं cut:

$ cut -d ' ' -f 2 <<< '-> s7-Gi0-0-1:1-US / Foo'
s7-Gi0-0-1:1-US

या आप प्रत्येक nth कॉलम का उपयोग करके प्रिंटawk कर सकते हैं :

$ awk -F' ' '{ for (i=2;i<=NF;i+=4) print $i }' <<< '-> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Foo'
r1-ae0-2
s7-Gi0-0-1:1-US
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.