शेल में एक स्ट्रिंग कैसे विभाजित करें और अंतिम फ़ील्ड प्राप्त करें


293

मान लीजिए कि मेरे पास स्ट्रिंग है 1:2:3:4:5और मैं इसका अंतिम क्षेत्र ( 5इस मामले में) प्राप्त करना चाहता हूं । मैं बैश का उपयोग कैसे करूँ? मैंने कोशिश की cut, लेकिन मुझे नहीं पता कि अंतिम फ़ील्ड को कैसे निर्दिष्ट किया जाए -f

जवाबों:


430

आप स्ट्रिंग ऑपरेटरों का उपयोग कर सकते हैं :

$ foo=1:2:3:4:5
$ echo ${foo##*:}
5

यह सब कुछ सामने से एक ':' तक, लालच से करता है।

${foo  <-- from variable foo
  ##   <-- greedy front trim
  *    <-- matches anything
  :    <-- until the last ':'
 }

7
जब यह दी गई समस्या के लिए काम कर रहा है, तो नीचे विलियम का जवाब ( stackoverflow.com/a/3163857/520162 ) भी लौटता है 5अगर स्ट्रिंग है 1:2:3:4:5:(स्ट्रिंग ऑपरेटरों का उपयोग करते समय एक खाली परिणाम देता है)। यह विशेष रूप से तब आसान होता है जब एक परिष्करण /चरित्र में पथ शामिल हो सकते हैं (या नहीं) ।
Eckes

9
फिर आप इसके विपरीत कैसे करेंगे? '1: 2: 3: 4:' को प्रतिध्वनित करने के लिए?
डोबज़

12
और कोई अंतिम विभाजक से पहले कैसे भाग रखता है? स्पष्ट रूप से उपयोग करके ${foo%:*}#- आरम्भ से; %- अंत से। #, %- सबसे छोटा मैच; ##, %%- सबसे लंबा मैच।
मिहाई डैनिला

1
यदि मुझे पथ से अंतिम तत्व प्राप्त करना है, तो मुझे इसका उपयोग कैसे करना चाहिए? echo ${pwd##*/}काम नहीं करता।
पुटनिक

2
@Putnik जो कमांड pwdएक चर के रूप में देखता है । कोशिश करो dir=$(pwd); echo ${dir##*/}। मेरे लिये कार्य करता है!
स्टेन स्ट्रम

344

दूसरा तरीका यह है कि पहले और बाद में उल्टा कर दिया जाए cut:

$ echo ab:cd:ef | rev | cut -d: -f1 | rev
ef

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


17
यह उत्तर अच्छा है क्योंकि यह 'कट' का उपयोग करता है, जिसे लेखक (संभवतः) पहले से परिचित है। इसके अलावा, मुझे यह उत्तर पसंद है क्योंकि मैं 'कट' का उपयोग कर रहा हूं और यह सटीक सवाल था, इसलिए इस धागे को खोज के माध्यम से ढूंढ रहा है।
दानीद १४'१३

6
कुछ कट-एंड-पेस्ट चारे को सीमांकक के रूप में उपयोग करने वाले लोगों के लिए:echo "1 2 3 4" | rev | cut -d " " -f1 | rev
19

2
रिवाइज | कट -d -f1 | रेव बहुत चालाक है! धन्यवाद! मुझे एक गुच्छा बनाने में मदद की (मेरा उपयोग मामला संशोधित था | -d '' -f 2-। | Rev
EdgeCaseBerg

1
मैं हमेशा के बारे में भूल जाते हैं rev, बस मुझे क्या चाहिए था! cut -b20- | rev | cut -b10- | rev
shearn89

मैं इस समाधान के साथ समाप्त हो गया, मेरे प्रयास ओ कट फ़ाइल पथ "awk -F" / "" {$ $ NF} "के साथ मेरे लिए कुछ हद तक टूट गया, क्योंकि सफेद रिक्त स्थान सहित फ़ाइल नाम भी कट गए
THX

76

कट का उपयोग करके अंतिम क्षेत्र प्राप्त करना मुश्किल है, लेकिन यहां कुछ समाधान हैं awk और perl

echo 1:2:3:4:5 | awk -F: '{print $NF}'
echo 1:2:3:4:5 | perl -F: -wane 'print $F[-1]'

5
स्वीकृत उत्तर पर इस समाधान का बहुत फायदा: यह उन रास्तों से भी मेल खाता है, जिनमें एक परिष्करण /चरित्र होता है या नहीं : /a/b/c/dऔर प्रसंस्करण के /a/b/c/d/दौरान उसी परिणाम ( d) का उत्पादन होता है pwd | awk -F/ '{print $NF}'। स्वीकृत उत्तर परिणाम के मामले में एक खाली परिणाम के रूप में होता है/a/b/c/d/
एक्यूस

@eckes AWU समाधान के मामले में, GNU बैश पर, संस्करण 4.3.48 (1) -release यह सच नहीं है, क्योंकि यह मायने रखता है कि जब भी आप स्लैश को पीछे छोड़ते हैं या नहीं। सीधे शब्दों में कहें तो AWK /सीमांकक के रूप में उपयोग करेगा , और यदि आपका मार्ग है /my/path/dir/तो अंतिम सीमांकक के बाद मान का उपयोग करेगा, जो बस एक खाली स्ट्रिंग है। इसलिए यदि आप को ऐसा करने की आवश्यकता है तो ट्रेसिंग स्लैश से बचना सबसे अच्छा है।
स्टैम्स्टर

मैं अंतिम फ़ील्ड को प्रतिस्थापित करने वाला UNTIL कैसे प्राप्त करूंगा?
ब्लैकजेनक्स

1
@blackjacx कुछ quirks हैं, लेकिन awk '{$NF=""; print $0}' FS=: OFS=:अक्सर ऐसा कुछ काम करता है जो काफी अच्छा होता है।
विलियम पर्ससेल

29

काफी सरल उपयोग मानते हुए (उदाहरण के लिए सीमांकक से बचना), आप grep का उपयोग कर सकते हैं:

$ echo "1:2:3:4:5" | grep -oE "[^:]+$"
5

ब्रेकडाउन - सभी पात्रों को लाइन के अंत में सीमांकक ([^:]) नहीं मिला ($)। -साथ ही मैचिंग पार्ट को प्रिंट करता है।


-ई का अर्थ है विस्तारित सिंटैक्स का उपयोग करना; [^ ...] कुछ भी लेकिन सूचीबद्ध चार का मतलब है; + एक या अधिक ऐसी हिट (पैटर्न के लिए अधिकतम संभव लंबाई लेगी; यह आइटम एक ग्नू एक्सटेंशन है) - उदाहरण के लिए अलग करने वाले चार (ओं) बृहदान्त्र हैं।
अलेक्जेंडर स्टोह्र

18

एक रास्ता:

var1="1:2:3:4:5"
var2=${var1##*:}

एक और, एक सरणी का उपयोग कर:

var1="1:2:3:4:5"
saveIFS=$IFS
IFS=":"
var2=($var1)
IFS=$saveIFS
var2=${var2[@]: -1}

फिर भी एक और सरणी के साथ:

var1="1:2:3:4:5"
saveIFS=$IFS
IFS=":"
var2=($var1)
IFS=$saveIFS
count=${#var2[@]}
var2=${var2[$count-1]}

बैश का उपयोग करना (संस्करण> = 3.2) नियमित अभिव्यक्ति:

var1="1:2:3:4:5"
[[ $var1 =~ :([^:]*)$ ]]
var2=${BASH_REMATCH[1]}

11
$ echo "a b c d e" | tr ' ' '\n' | tail -1
e

बस एक नई सीमा में सीमांकक का अनुवाद करें और अंतिम प्रविष्टि चुनें tail -1


यह विफल हो जाएगा यदि अंतिम आइटम में ए है \n, लेकिन अधिकांश मामलों के लिए सबसे पठनीय समाधान है।
येजो

7

का उपयोग कर sed:

$ echo '1:2:3:4:5' | sed 's/.*://' # => 5

$ echo '' | sed 's/.*://' # => (empty)

$ echo ':' | sed 's/.*://' # => (empty)
$ echo ':b' | sed 's/.*://' # => b
$ echo '::c' | sed 's/.*://' # => c

$ echo 'a' | sed 's/.*://' # => a
$ echo 'a:' | sed 's/.*://' # => (empty)
$ echo 'a:b' | sed 's/.*://' # => b
$ echo 'a::c' | sed 's/.*://' # => c

4

यदि आपका अंतिम क्षेत्र एकल वर्ण है, तो आप ऐसा कर सकते हैं:

a="1:2:3:4:5"

echo ${a: -1}
echo ${a:(-1)}

बैश में स्ट्रिंग हेरफेर की जाँच करें ।


यह काम नहीं करता: यह पिछले देता है चरित्र की aआखिरी, नहीं क्षेत्र
गनीउर_ग्निउरफ

1
यह सच है, यह विचार है, यदि आप जानते हैं कि अंतिम क्षेत्र की लंबाई अच्छी है। यदि आपको कुछ और उपयोग नहीं करना है ...
Ab Irato

4

यहाँ कई अच्छे उत्तर हैं, लेकिन फिर भी मैं इसे बेसनेम का उपयोग करके साझा करना चाहता हूं :

 basename $(echo "a:b:c:d:e" | tr ':' '/')

हालांकि यह विफल हो जाएगा अगर आपके तार में पहले से ही कुछ '/' हैं । यदि स्लैश / आपका सीमांकक है तो आपको बस (और) को बेसन का उपयोग करना चाहिए।

यह सबसे अच्छा जवाब नहीं है, लेकिन यह सिर्फ यह दर्शाता है कि आप बैश कमांड का उपयोग करके कैसे रचनात्मक हो सकते हैं।


2

बैश का उपयोग करना।

$ var1="1:2:3:4:0"
$ IFS=":"
$ set -- $var1
$ eval echo  \$${#}
0

की echo ${!#}जगह इस्तेमाल कर सकते थे eval echo \$${#}
रफ़ा

2
echo "a:b:c:d:e"|xargs -d : -n1|tail -1

पहले xargs का उपयोग करके इसे ":", - n1 से विभाजित करें, इसका मतलब है कि हर पंक्ति में केवल एक भाग होता है। फिर, अंतिम भाग को आगे बढ़ाते हैं।


1
for x in `echo $str | tr ";" "\n"`; do echo $x; done

2
यह किसी भी क्षेत्र में व्हाट्सएप होने पर समस्याओं में चलता है। साथ ही, यह अंतिम फ़ील्ड को पुनर्प्राप्त करने के प्रश्न को सीधे संबोधित नहीं करता है ।
१२

1

उन लोगों के लिए जो पाइथन के साथ सहज हैं, https://github.com/Russell91/pythonpy इस समस्या को हल करने के लिए एक अच्छा विकल्प है।

$ echo "a:b:c:d:e" | py -x 'x.split(":")[-1]'

अजगर की मदद से -x treat each row of stdin as x:।

उस टूल के साथ, अजगर कोड लिखना आसान है जो इनपुट पर लागू होता है।


1

उत्तर के साथ थोड़ा देर हो सकती है हालांकि इनपुट स्ट्रिंग के आदेश को उलटने के लिए एक सरल समाधान है। यह आपको हमेशा अंतिम आइटम हासिल करने की अनुमति देगा चाहे कोई भी लंबाई क्यों न हो।

[chris@desktop bin]$ echo 1:2:3:4:5 | rev | cut -d: -f1
5

हालांकि यह नोट करना महत्वपूर्ण है, अगर इस पद्धति और संख्याओं का उपयोग 1 अंक (या किसी भी परिस्थिति में एक वर्ण से बड़ा) से बड़ा है, तो आपको पाइप्ड आउटपुट पर एक और 'रेव' कमांड चलाने की आवश्यकता होगी।

[chris@desktop bin]$ echo 1:2:3:4:5:8:24 | rev | cut -d: -f1
42
[chris@desktop bin]$ echo 1:2:3:4:5:8:24 | rev | cut -d: -f1 | rev
24

आशा है कि मैं मदद कर सकता हूँ, चीयर्स


1

रीड बिलिन का उपयोग कर एक समाधान:

IFS=':' read -a fields <<< "1:2:3:4:5"
echo "${fields[4]}"

या, इसे और अधिक सामान्य बनाने के लिए:

echo "${fields[-1]}" # prints the last item

0

यदि आपको अजगर पसंद है और आपके पास पैकेज स्थापित करने का विकल्प है, तो आप इस अजगर उपयोगिता का उपयोग कर सकते हैं ।

# install pythonp
pythonp -m pip install pythonp

echo "1:2:3:4:5" | pythonp "l.split(':')[-1]"
5

अजगर सीधे यह कर सकता है: echo "1:2:3:4:5" | python -c "import sys; print(list(sys.stdin)[0].split(':')[-1])"
मोर्टेनब

@MortenB आप गलत हैं। pythonpपैकेज का पूरा उद्देश्य आपको python -cकम चरित्र टाइपिंग के साथ ही काम करना है । कृपया भंडार में README पर एक नज़र डालें।
बम

0

रेग्क्स का मिलान sedलालची है (हमेशा अंतिम घटना तक जाता है), जिसका उपयोग आप यहां अपने लाभ के लिए कर सकते हैं:

$ foo=1:2:3:4:5
$ echo ${foo} | sed "s/.*://"
5
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.