बैश में एक स्ट्रिंग से एक निश्चित उपसर्ग / प्रत्यय निकालें


484

मेरे में bash स्क्रिप्ट में मेरे पास एक स्ट्रिंग और इसके उपसर्ग / प्रत्यय हैं। मुझे मूल स्ट्रिंग से उपसर्ग / प्रत्यय निकालने की आवश्यकता है।

उदाहरण के लिए, मान लें कि मेरे पास निम्नलिखित मूल्य हैं:

string="hello-world"
prefix="hell"
suffix="ld"

मैं निम्नलिखित परिणाम कैसे प्राप्त करूं?

result="o-wor"


14
तथाकथित बैश स्क्रिप्टिंग गाइड से लिंक करते समय बहुत सावधान रहें; इसमें अच्छी सलाह और भयानक का मिश्रण होता है।
ट्रिपलए

जवाबों:


718
$ foo=${string#"$prefix"}
$ foo=${foo%"$suffix"}
$ echo "${foo}"
o-wor

40
## और %% भी हैं, जो $ उपसर्ग या $ प्रत्यय में वाइल्डकार्ड होते हैं, जितना संभव हो उतना हटा देते हैं।
अंक

27
क्या दोनों को एक पंक्ति में मिलाने का कोई तरीका है? मैंने कोशिश की, ${${string#prefix}%suffix}लेकिन यह काम नहीं करता है।
static_rtti

28
@static_rtti नहीं, दुर्भाग्य से आप इस तरह पैरामीटर प्रतिस्थापन नहीं कर सकते। मुझे पता है, यह शर्म की बात है।
एड्रियन फ्रुविर्थ

87
@ AdrianFrühwirth: पूरी भाषा एक शर्म की बात है, लेकिन यह बहुत उपयोगी है :)
static_rtti

8
एनवीएम, Google में "बैश प्रतिस्थापन" पाया गया जो मुझे चाहिए था।
टायलर

89

Sed का उपयोग करना:

$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor

Sed कमांड के भीतर, ^कैरेक्टर के साथ शुरू होने वाले टेक्स्ट से मेल खाता है $prefix, और पीछे चल $रहे टेक्स्ट से मेल खाता है$suffix

एड्रियन फ्रुविर्थ नीचे दी गई टिप्पणियों में कुछ अच्छे अंक बनाते हैं, लेकिन sedइस उद्देश्य के लिए बहुत उपयोगी हो सकते हैं। यह तथ्य कि तलछट द्वारा $ उपसर्ग और $ प्रत्यय की सामग्री की व्याख्या अच्छी या बुरी हो सकती है- जब तक आप ध्यान देते हैं, आपको ठीक होना चाहिए। सुंदरता यह है कि आप कुछ इस तरह से कर सकते हैं:

$ prefix='^.*ll'
$ suffix='ld$'
$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor

हो सकता है कि आप क्या चाहते हैं, और दोनों कट्टरपंथी और बैश चर प्रतिस्थापन की तुलना में अधिक शक्तिशाली हो। यदि आपको याद है कि महान शक्ति के साथ बड़ी जिम्मेदारी आती है (जैसा कि स्पाइडरमैन कहता है), तो आपको ठीक होना चाहिए।

सेड का शीघ्र परिचय पाया जा सकता है http://evc-cit.info/cit052/sed_tutorial.html

खोल और तार के उपयोग के बारे में एक नोट:

दिए गए विशेष उदाहरण के लिए, निम्नलिखित भी काम करेगा:

$ echo $string | sed -e s/^$prefix// -e s/$suffix$//

... लेकिन केवल इसलिए:

  1. गूंज यह परवाह नहीं करती है कि इसके तर्क सूची में कितने तार हैं, और
  2. $ उपसर्ग और $ प्रत्यय में कोई स्थान नहीं हैं

यह आमतौर पर कमांड लाइन पर एक स्ट्रिंग को उद्धृत करने के लिए अच्छा अभ्यास है क्योंकि यहां तक ​​कि अगर इसमें रिक्त स्थान हैं, तो इसे एक ही तर्क के रूप में कमांड में प्रस्तुत किया जाएगा। हम एक ही कारण के लिए $ प्रीफिक्स और $ प्रत्यय का उद्धरण करते हैं: प्रत्येक एडिट कमांड टू सेड को एक स्ट्रिंग के रूप में पास किया जाएगा। हम दोहरे उद्धरण चिह्नों का उपयोग करते हैं क्योंकि वे परिवर्तनीय प्रक्षेप के लिए अनुमति देते हैं; क्या हमने सिंगल कोट्स का इस्तेमाल किया था, तो कमांड ने एक शाब्दिक रूप दिया होगा $prefixऔर $suffixनिश्चित रूप से वह नहीं था जो हम चाहते थे।

नोटिस, भी, चर सेट करते समय मेरे एकल उद्धरण का उपयोग prefixऔर suffix। हम निश्चित रूप से स्ट्रिंग्स में कुछ भी व्याख्या नहीं करना चाहते हैं, इसलिए हम उन्हें उद्धृत करते हैं ताकि कोई प्रक्षेप न हो। फिर, यह इस उदाहरण में आवश्यक नहीं हो सकता है, लेकिन यह एक बहुत अच्छी आदत है।


8
दुर्भाग्य से, यह कई कारणों से बुरी सलाह है: 1) अयोग्य, $stringशब्द विभाजन और ग्लोबिंग के अधीन है। 2) $prefixऔर $suffixइसमें ऐसे भाव हो सकते हैं जो sedव्याख्या करेंगे, उदाहरण के लिए नियमित अभिव्यक्तियाँ या चरित्र जिसे सीमांकक के रूप में उपयोग किया जाता है जो पूरी कमांड को तोड़ देगा। 3) sedदो बार कॉल करना आवश्यक नहीं है (आप -e 's///' -e '///'इसके बजाय) और पाइप से भी बचा जा सकता है। उदाहरण के लिए, विचार करें string='./ *'और / या prefix='./'देखें और इसे तोड़ने के कारण 1)और 2)
एड्रियन फ्रुविर्थ

मजेदार टिप्पणी: सीड लगभग किसी भी चीज़ को सीमांकक के रूप में ले सकता है मेरे मामले में, चूंकि मैं रास्तों से पहले उपसर्गों-निर्देशिकाओं को पार्स कर रहा था /, इसलिए मैं उपयोग नहीं कर सकता था , इसलिए मैंने sed "s#^$prefix##इसके बजाय उपयोग किया । (नाजुकता: फ़ाइल नाम शामिल नहीं हो सकते #। चूंकि मैं फ़ाइलों को नियंत्रित करता हूं, हम सुरक्षित हैं, वहां।)
ओली

@ कोई भी फ़ाइलनाम स्लैश और अशक्त चरित्र को छोड़कर किसी भी वर्ण को समाहित कर सकता है, जब तक कि आप नियंत्रण में न हों आप कुछ वर्णों को शामिल नहीं करने के लिए फ़ाइल नाम नहीं मान सकते।
एड्रियन फ्रुविर्थ

हाँ, पता नहीं मैं वहाँ क्या सोच रहा था। आईओएस हो सकता है? पता नहीं। फ़ाइलनाम में निश्चित रूप से "#" हो सकता है। पता नहीं मैंने ऐसा क्यों कहा। :)
ओले

@ ओली: जैसा कि मैंने आपकी मूल टिप्पणी को समझा, आप कह रहे थे कि #सीड के सीमांकक के रूप में उपयोग करने के लिए आपकी पसंद की सीमा का मतलब है कि आप उस चरित्र वाली फ़ाइलों को संभाल नहीं सकते।
पी डैडी

17

क्या आप अपने उपसर्ग और प्रत्यय की लंबाई जानते हैं? आपके मामले में:

result=$(echo $string | cut -c5- | rev | cut -c3- | rev)

या अधिक सामान्य:

result=$(echo $string | cut -c$((${#prefix}+1))- | rev | cut -c$((${#suffix}+1))- | rev)

लेकिन एड्रियन फ्रुविर्थ से समाधान अच्छा है! मुझे उस बारे में पता नहीं था!


14

मैं रास्ते से उपसर्ग (जो अच्छी तरह से नियंत्रित नहीं किया जाता है sed) को हटाने के लिए grep का उपयोग करता हूं :

echo "$input" | grep -oP "^$prefix\K.*"

\K मैच से पहले सभी पात्रों को हटा देता है।


grep -Pएक गैरमानक विस्तार है। यदि आपके प्लेटफ़ॉर्म पर इसका समर्थन किया जाता है, तो आपको अधिक शक्ति मिलेगी, लेकिन यह संदिग्ध सलाह है यदि आपके कोड को यथोचित पोर्टेबल होने की आवश्यकता है।
ट्रिपलआई

@tripleee वास्तव में। लेकिन मुझे लगता है कि स्थापित GNU बैश के साथ एक सिस्टम भी एक grep है जो PCRE का समर्थन करता है।
व्लादिमीर पेत्राकोविच

1
नहीं, उदाहरण के लिए MacOS बॉक्स से बाहर बैश है लेकिन GNU नहीं है grep। पहले के संस्करणों में वास्तव में -Pबीएसडी का विकल्प था grepलेकिन उन्होंने इसे हटा दिया।
ट्रिपलआई

9
$ string="hello-world"
$ prefix="hell"
$ suffix="ld"

$ #remove "hell" from "hello-world" if "hell" is found at the beginning.
$ prefix_removed_string=${string/#$prefix}

$ #remove "ld" from "o-world" if "ld" is found at the end.
$ suffix_removed_String=${prefix_removed_string/%$suffix}
$ echo $suffix_removed_String
o-wor

टिप्पणियाँ:

# $ उपसर्ग: जोड़ना # यह सुनिश्चित करता है कि "नरक" को प्रतिस्थापित करना केवल तभी शुरू होता है जब यह शुरुआत में पाया जाता है। % $ प्रत्यय:% जोड़ने से यह सुनिश्चित होता है कि "ld" को प्रतिस्थापित करना केवल तभी निकाला जाता है जब यह अंत में पाया जाता है।

इन के बिना, सबस्ट्रिंग "नरक" और "एलडी" हर जगह हटा दिया जाएगा, यहां तक ​​कि यह बीच में पाया जाता है।


नोट्स के लिए धन्यवाद! qq: आपके कोड उदाहरण में आपके पास /स्ट्रिंग के ठीक बाद एक आगे की स्लैश है , वह किस लिए है?
डिएगासलाज़ार

1
/ वर्तमान स्ट्रिंग और उप स्ट्रिंग को अलग करता है। यहाँ उप-स्ट्रिंग वें पोस्ट किए गए प्रश्न में प्रत्यय है।
विजय वट


6

छोटे और सार्वभौमिक समाधान:

expr "$string" : "$prefix\(.*\)$suffix"

1
यदि आप बैश का उपयोग कर रहे हैं, तो आपको संभवतः बिल्कुल भी उपयोग नहीं करना चाहिए expr। यह मूल बॉर्न शेल के दिनों में एक तरह का सुविधाजनक किचन सिंक यूटिलिटी था, लेकिन अब इसकी सबसे अच्छी डेट से पहले का रास्ता है।
ट्रिपलआई

5

@ Adrian Frühwirth उत्तर का उपयोग करना:

function strip {
    local STRING=${1#$"$2"}
    echo ${STRING%$"$2"}
}

इसे इस तरह से उपयोग करें

HELLO=":hello:"
HELLO=$(strip "$HELLO" ":")
echo $HELLO # hello

0

मैं regex में कैप्चर समूहों का उपयोग करूंगा:

$ string="hello-world"
$ prefix="hell"
$ suffix="ld"
$ set +H # Disables history substitution, can be omitted in scripts.
$ perl -pe "s/${prefix}((?:(?!(${suffix})).)*)${suffix}/\1/" <<< $string
o-wor
$ string1=$string$string
$ perl -pe "s/${prefix}((?:(?!(${suffix})).)*)${suffix}/\1/g" <<< $string1
o-woro-wor

((?:(?!(${suffix})).)*)सुनिश्चित करता है कि सामग्री ${suffix}को कैप्चर समूह से बाहर रखा जाएगा। उदाहरण के लिए, यह स्ट्रिंग के बराबर है [^A-Z]*। अन्यथा आपको मिलेगा:

$ perl -pe "s/${prefix}(.*)${suffix}/\1/g" <<< $string1
o-worldhello-wor
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.