बृहदान्त्र पर / बिन / श में विभाजित स्ट्रिंग


9

मेरी dashस्क्रिप्ट के रूप में एक पैरामीटर लेता है hostname:port, अर्थात:

myhost:1234

जबकि पोर्ट वैकल्पिक है, अर्थात:

myhost

मुझे होस्ट और पोर्ट को अलग-अलग वेरिएबल में पढ़ने की जरूरत है। पहले मामले में, मैं कर सकता हूँ:

HOST=${1%%:*}
PORT=${1##*:}

लेकिन यह दूसरे मामले में काम नहीं करता है, जब बंदरगाह छोड़ा गया था; echo ${1##*:}खाली स्ट्रिंग के बजाय केवल होस्टनाम लौटाता है।

बैश में, मैं कर सकता था:

IFS=: read A B <<< asdf:111

लेकिन वह काम नहीं करता है dash

मैं पर स्ट्रिंग विभाजित कर सकते हैं :पानी का छींटा में, बाहरी प्रोग्राम (लागू बिना awk, tr, आदि)?


4
यदि आप IPv6 का समर्थन करना चाहते हैं, तो अंतिम बृहदान्त्र पर विभाजित करना सुनिश्चित करें, और वर्ग कोष्ठक के अंदर
कॉलोनों

@ फेरीबग %%इसे लालची बनाता है (विरोध के रूप में %), इसलिए यह वास्तव में ऐसा करता है, कम से कम भाग में; यह साथ काम नहीं करेगा ##
jpaugh

जवाबों:


18

बस करो:

case $1 in
  (*:*) host=${1%:*} port=${1##*:};;
  (*)   host=$1      port=$default_port;;
esac

आप को बदलने के लिए चाहते हो सकता है case $1के लिए case ${1##*[]]}के मूल्यों के लिए खाते में $1की तरह [::1](बिना कोई IPv6 पता बंदरगाह भाग)।

विभाजित करने के लिए, आप विभाजन + ग्लोब ऑपरेटर का उपयोग कर सकते हैं (एक पैरामीटर विस्तार को न छोड़ें) जैसा कि सभी के लिए है:

set -o noglob # disable glob part
IFS=:         # split on colon
set -- $1     # split+glob

host=$1 port=${2:-$default_port}

(हालांकि यह उन होस्टनामों को अनुमति नहीं देगा जिनमें एक बृहदान्त्र होता है (जैसे कि IPv6 पता ऊपर)।

यह विभाजन + ग्लोब ऑपरेटर रास्ते में हो जाता है और शेष समय को इतना नुकसान पहुंचाता है कि यह केवल उचित प्रतीत होगा कि इसका उपयोग जब भी आवश्यक हो (हालांकि, मैं सहमत हूँ कि यह विशेष रूप से यह देखते हुए उपयोग करने के लिए बहुत बोझिल है कि POSIX के shपास कोई नहीं है स्थानीय दायरे के लिए समर्थन, न तो चर ( $IFSयहां) के लिए और न ही विकल्पों के लिए ( noglobयहां) (हालांकि ashऔर डेरिवेटिव की तरह dashकुछ हैं जो एटी एंड टी के कार्यान्वयन ksh( zshऔर bash4.4 और ऊपर) के साथ करते हैं।

ध्यान दें कि IFS=: read A B <<< "$1"इसके कुछ मुद्दे हैं:

  • आप भूल गए -rजिसका मतलब है कि बैकस्लैश कुछ विशेष प्रसंस्करण से गुजरना होगा।
  • इसे विभाजित हैं [::1]:443में [और :1]:443के बजाय [और रिक्त स्ट्रिंग (जिसके लिए आप आवश्यकता होगी IFS=: read -r A B rest_ignoredया [::1]और 443(जिसके लिए आपको लगता है कि दृष्टिकोण का उपयोग नहीं कर सकते हैं)
  • यह अतीत एक नई पंक्ति चरित्र की पहली आवृत्ति सब कुछ स्ट्रिप्स, तो यह (मनमाने ढंग से तार के साथ नहीं किया जा सकता जब तक कि आप का उपयोग -d ''में zshया bashऔर डेटा NUL वर्ण नहीं है, लेकिन फिर ध्यान दें कि herestrings (या heredocs) एक जोड़ सकता हूँ अतिरिक्त न्यूलाइन वर्ण!)
  • में zsh(जहाँ सिंटैक्स आता है) और bash, यहाँ अस्थायी फ़ाइलों का उपयोग करके स्ट्रिंग्स को लागू किया जाता है, इसलिए यह आमतौर पर ${x#y}+ संचालकों के उपयोग या विभाजन से कम कुशल है ।

7
2018 में, नए साल के संकल्प के रूप में, हम सभी को स्क्रिप्ट लिखना बंद कर देना चाहिए जो आईपीवी 6 के साथ टूट जाएगा।
Philippos

@Philippos में दो हफ्ते की देरी!
रॉनजॉन

@ रॉन जॉन: दो दशक से बहुत देर से, किसी तरह।
फिलिप्प्स

6

बस :एक अलग बयान में निकालें ; पोर्ट प्राप्त करने के लिए इनपुट से $ होस्ट को भी निकालें:

host=${1%:*}
port=${1#"$host"}
port=${port#:}


1

यहाँ एक स्ट्रिंग यहाँ दस्तावेज़ के लिए सिंगल-लाइन के लिए एक सिंटैक्टिक शॉर्टकट है।

$ set myhost:1234
$ IFS=: read A B <<EOF
> $1
> EOF
$ echo "$A"
myhost
$ echo "B"
1234
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.