सीमांकक द्वारा विभाजित स्ट्रिंग और एन-वें तत्व प्राप्त करें


75

मेरे पास एक स्ट्रिंग है:

one_two_three_four_five

मैं एक चर में बचाने की जरूरत है Aमूल्य twoऔर चर में Bमूल्य fourसे ऊपर स्ट्रिंग से

जवाबों:


105

का प्रयोग करें cutसाथ _क्षेत्र परिसीमक के रूप में और वांछित क्षेत्रों मिलती है:

A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"

आप echoयहां स्ट्रिंग के बजाय उपयोग और पाइप कर सकते हैं :

A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"

उदाहरण:

$ s='one_two_three_four_five'

$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two

$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four

क्या कोई विकल्प है? मैं ksh (bsh नहीं) का उपयोग कर रहा हूं और यह ksh: सिंटैक्स त्रुटि देता है: `<'अनपेक्षित
एलेक्स

@Alex मेरे संपादन की जाँच करें।
heemayl

अच्छा जवाब, मेरे पास एक छोटा सा सवाल है: अगर आपका चर "$ s" एक पथ फ़ोल्डर है तो क्या होगा। जब मैं एक पथ फ़ोल्डर को काटने की कोशिश करता हूं जिसे मैं निम्न प्रकार करता हूं: `$ FILE = my_user / my_folder / [file] *` $ echo $FILE my_user/my_folder/file.csv $ A="$(cut -d'/' -f2 <<<"$FILE")" $ echo $A [file]* क्या आप जानते हैं कि यहां क्या हो रहा है?
हेनरी नवारो

1
और यदि आप केवल अंतिम क्षेत्र चाहते हैं, केवल शेल बिल्डरों का उपयोग करके - अपनी स्थिति को निर्दिष्ट करने की आवश्यकता के बिना, या जब आप फ़ील्ड्स की संख्या नहीं जानते हैं:echo "${s##*_}"
अमित नायडू

19

केवल POSIX sh कंस्ट्रक्शंस का उपयोग करके, आप एक समय में एक सीमांकक को पार्स करने के लिए पैरामीटर प्रतिस्थापन निर्माण का उपयोग कर सकते हैं । ध्यान दें कि यह कोड मानता है कि फ़ील्ड की अपेक्षित संख्या है, अन्यथा अंतिम फ़ील्ड दोहराया जाता है।

string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"

वैकल्पिक रूप से, आप वाइल्डकार्ड विस्तार के साथ एक अनियोजित पैरामीटर प्रतिस्थापन का उपयोग कर सकते हैं और IFSसीमांकित चरित्र पर सेट किया जाता है (यह केवल तभी काम करता है जब सीमांकक एक एकल नॉन-व्हाट्सएप चरित्र है या यदि कोई व्हाट्सएप अनुक्रम सीमांकक है)।

string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS

यह स्थितिगत मापदंडों को स्पष्ट करता है। यदि आप किसी फ़ंक्शन में ऐसा करते हैं, तो केवल फ़ंक्शन के स्थितीय पैरामीटर प्रभावित होते हैं।

फिर भी एक अन्य दृष्टिकोण readबिलिन का उपयोग करना है ।

IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF

के उपयोग unset IFSवापस नहीं करता है IFSडिफ़ॉल्ट करने के लिए। यदि उसके बाद कोई करता है OldIFS="$IFS"तो OldIFS के अंदर एक अशक्त मूल्य होगा। इसके अलावा, यह मान लिया गया है कि IFS का पिछला मान डिफ़ॉल्ट है, जो नहीं होना बहुत संभव (और उपयोगी) है। एकमात्र सही समाधान old="$IFS"IFS = "$ पुराने" के साथ स्टोर करना और बाद में पुनर्स्थापित करना है। या ... एक उप-शेल का उपयोग करें (...)। या, बेहतर अभी तक, मेरा जवाब पढ़ें।
सोरोंटर

@sorontar डिफ़ॉल्ट मान को unset IFSपुनर्स्थापित नहीं करता है IFS, लेकिन यह डिफ़ॉल्ट प्रभाव के लिए क्षेत्र को विभाजित करता है। हां, यह एक सीमा है, लेकिन आमतौर पर व्यवहार में एक स्वीकार्य है। एक उपधारा के साथ समस्या यह है कि हमें इससे डेटा प्राप्त करने की आवश्यकता है। मैं एक समाधान दिखाता हूं जो राज्य को अंत में नहीं बदलता है, के साथ read। (यह POSIX गोले में काम करता है, लेकिन IIRC बॉर्न शेल में नहीं है क्योंकि यह readयहाँ-दस्तावेज़ के कारण उप- भाग में चलेगा ।) <<<जैसा कि आप उत्तर में उपयोग कर रहे हैं, जो केवल ksh / bash / zsh में काम करता है।
गाइल्स

मुझे किसी समस्या के बारे में भी नहीं दिख रहा है जैसे कि उप या शेलर शेल के बारे में। परीक्षण किए गए सभी गोले (पुराने बोर्न सहित) मुख्य शेल में सही मूल्य प्रदान करते हैं।
सोरोंटर

अगर मेरा रास्ता कुछ ऐसा है तो क्या होगा user/my_folder/[this_is_my_file]*? जब मैं इन चरणों का पालन करता हूं तो मुझे क्या मिलता है[this_is_my_file]*
हेनरी नवारो

@HenryNavarro यह आउटपुट मेरे उत्तर में किसी भी कोड स्निपेट के अनुरूप नहीं है। उनमें से कोई भी कुछ खास नहीं करता है /
गिल्स

17

एक awkजवाब देखना चाहता था , तो यहाँ एक है:

A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')

1
और अगर आप अंतिम टुकड़ा चाहते हैं - अपनी स्थिति को निर्दिष्ट करने की आवश्यकता के बिना या जब आप खेतों की संख्या नहीं जानते हैं:awk -F_ '{print $NF}' <<< 'one_two_3_4_five'
अमित नायडू

8

सबसे सरल तरीका (<<< के साथ गोले के लिए) है:

 IFS='_' read -r a second a fourth a <<<"$string"

एक शेल के $aबजाय एक अस्थायी चर का उपयोग करना $_

एक पूर्ण स्क्रिप्ट में:

 string='one_two_three_four_five'
 IFS='_' read -r a second a fourth a <<<"$string"
 echo "$second $fourth"

कोई IFS नहीं बदल रहा है, set -f(Pathname विस्तार) के साथ कोई समस्या नहीं है, स्थितिगत मापदंडों में कोई बदलाव नहीं ("$ @")।


सभी गोले के लिए पोर्टेबल समाधान के लिए (हाँ, सभी POSIX शामिल) IFS को बदलने के बिना या set -f, (थोड़ा और अधिक जटिल) heredoc समकक्ष का उपयोग करें:

string='one_two_three_four_five'

IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_

echo "$second $fourth"

यह समझें कि यह समाधान (दोनों यहाँ-डॉक्टर और उपयोग के <<<सभी नए सिरे को हटा देगा।
और यह कि इसे "वन लाइनर" वैरिएबल सामग्री के लिए डिज़ाइन किया गया है।
मल्टी-लाइनर्स के लिए समाधान संभव है लेकिन अधिक जटिल निर्माणों की आवश्यकता है।


बश संस्करण 4.4 में एक बहुत ही सरल समाधान संभव है

readarray -d _ -t arr <<<"$string"

echo "array ${arr[1]} ${arr[3]}"   # array numbers are zero based.

POSIX गोले के लिए कोई समकक्ष नहीं है, क्योंकि कई POSIX गोले में सरणियाँ नहीं हैं।

उन गोले के लिए, जिनके पास सरणियाँ सरल हो सकती हैं:
(attsh, lksh, mksh, ksh, और bash में काम किया गया परीक्षण)

set -f; IFS=_; arr=($string)

लेकिन चर और विकल्पों को रखने और रीसेट करने के लिए बहुत सी अतिरिक्त पाइपलाइनों के साथ:

string='one_* *_three_four_five'

case $- in
    *f*) noglobset=true; ;;
    *) noglobset=false;;
esac

oldIFS="$IFS"

set -f; IFS=_; arr=($string)

if $noglobset; then set -f; else set +f; fi

echo "two=${arr[1]} four=${arr[3]}"

Zsh में, सरणियाँ 1 में शुरू होती हैं, और डिफ़ॉल्ट रूप से स्ट्रिंग को विभाजित नहीं करती हैं।
इसलिए इस काम को करने के लिए कुछ बदलाव करने की जरूरत है।


समाधान है कि उपयोग के read रूप में लंबे समय के रूप में सरल कर रहे हैं जब तक ओपी 76 वें और 127 वें तत्वों को एक लंबी स्ट्रिंग से बाहर निकालना नहीं चाहता ...
don_crissti

@don_crissti खैर, हां, बिल्कुल, लेकिन एक समान निर्माण: readarrayउस स्थिति के लिए उपयोग करना आसान हो सकता है।
सोरोन्टर

@don_crissti मैंने ऐसे गोले के लिए एक सरणी समाधान भी जोड़ा है जिसमें सरणियाँ हैं। POSIX गोले के लिए, अच्छी तरह से, सरणियाँ नहीं होने से, 127 तत्वों तक की स्थितिगत पैरामीटर किसी भी उपाय से "सरल" समाधान नहीं है।
सोरोन्टर

2

आपके साथ zshस्ट्रिंग को (पर _) एक सरणी में विभाजित किया जा सकता है :

elements=(${(s:_:)string})

और फिर प्रत्येक / किसी भी तत्व को ऐरे इंडेक्स के माध्यम से एक्सेस करें:

print -r ${elements[4]}

ध्यान रखें कि zsh(विपरीत ksh/ bash) सरणी सूचकांक 1 से शुरू होते हैं


कृपया set -fपहले समाधान के लिए चेतावनी जोड़ना याद रखें । ... तारांकन *शायद?
19

@ सटोरेंट - आपको क्यों लगता है कि मुझे ज़रूरत है set -f? मैं उपयोग नहीं कर रहा हूँ read/ IFS। मेरे समाधान को एक स्ट्रिंग की तरह *_*_*या जो भी कोशिश करें ...
don_crissti

Zsh के लिए नहीं, लेकिन उपयोगकर्ता ने ksh समाधान के लिए कहा, इसलिए, वह उस शेल में इसका उपयोग करने का प्रयास कर सकता है। एक चेतावनी उसे समस्या से बचने में मदद करेगी।
सोरोंटर

1

क्या एक अजगर समाधान की अनुमति है?

# python -c "import sys; print sys.argv[1].split('_')[1]" one_two_three_four_five
two

# python -c "import sys; print sys.argv[1].split('_')[3]" one_two_three_four_five
four

नंबर खराब खराब उत्तर
राज कुमार

0

एक और जागृत उदाहरण; समझने में सरल।

A=\`echo one_two_three_four_five | awk -F_ '{print $1}'\`  
B=\`echo one_two_three_four_five | awk -F_ '{print $2}'\`  
C=\`echo one_two_three_four_five | awk -F_ '{print $3}'\`  
... and so on...  

चर के साथ भी इस्तेमाल किया जा सकता है।
मान लीजिए:
this_str = "one_two_three_four_five"
फिर निम्नलिखित कार्य करता है:
A = `प्रतिध्वनि $ {this_str} | awk -F_ '{प्रिंट $ 1}' `
B =` प्रतिध्वनि $ {this_str} | awk -F_ '{प्रिंट $ 2}' `
C =` प्रतिध्वनि $ {this_str} | awk -F_ '{प्रिंट $ 3}' `
... इत्यादि ...

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