कैसे एक सरणी में एक सीमांकित स्ट्रिंग विभाजित करने के लिए?


169

जब उसमें पाइप के चिन्ह होते हैं तो स्ट्रिंग को कैसे विभाजित |किया जाए। मैं सरणी में होने के लिए उन्हें विभाजित करना चाहता हूं।

मैंने कोशिश की

echo "12:23:11" | awk '{split($0,a,":"); print a[3] a[2] a[1]}'

जो ठीक काम करता है। यदि मेरी स्ट्रिंग जैसी है "12|23|11"तो मैं उन्हें एक सरणी में कैसे विभाजित करूं?


3
ध्यान दें कि आपका आउटपुट सरणी तत्वों को अलग कर रहा है, जिसमें कोई विभाजक नहीं है। यदि आप इसके बजाय उन्हें अलग करना चाहते हैं OFS, तो उनके बीच अल्पविराम, printउन्हें अलग-अलग तर्क के रूप में देखें।
डब्यूजिम

या आप sed का उपयोग कर सकते हैं:echo "12:23:11" | sed "s/.*://"
slushy

@ सुशी: आपकी आज्ञा बिल्कुल नहीं है जो पूछने वाले की जरूरत है। आपकी कमांड ( echo "12:23:11" | sed "s/.*://") अंतिम ": (" सहित) तक सब कुछ हटा दें: ", केवल" 11 "रखते हुए ... यह अंतिम संख्या प्राप्त करने के लिए काम करता है, लेकिन प्राप्त करने के लिए (एक मुश्किल तरीके से) संशोधित करने की आवश्यकता होगी दूसरी संख्या, आदि awk (और awk का विभाजन) अधिक सुंदर और पठनीय है।
ओलिवियर दुलैक

यदि आपको किसी एकल पात्र पर विभाजित करने की आवश्यकता है, तो आप उपयोग कर सकते हैंcut
ccpizza

जवाबों:


274

आपने कोशिश की है:

echo "12|23|11" | awk '{split($0,a,"|"); print a[3],a[2],a[1]}'

2
@ मोहम्मद सलीग, यदि आप सोलारिस पर हैं, तो आपको स्ट्रिंग लंबाई को देखते हुए / usr / xpg4 / bin / awk का उपयोग करने की आवश्यकता है ।
दिमित्रे रादौलोव

5
'मेरे लिए काम नहीं कर रहा है।' विशेष रूप से प्रतिध्वनित मूल्यों के बीच कॉलनों के साथ और विभाजित करने के लिए '?' लेखन त्रुटि है? सभी को सफलता मिले।
शेल्टर

1
कुछ वाक्यविन्यास स्पष्टीकरण के साथ बेहतर है।
एलस्टन

2
यह जीएनयू जाग में काम नहीं करेगा, क्योंकि तीसरा तर्क splitनियमित अभिव्यक्ति है, और |विशेष प्रतीक है, जिससे बचने की आवश्यकता है। उपयोगsplit($0, a, "\|")
व्हाइटविंड

1
@WhiteWind: "सुनिश्चित" करने का एक और तरीका जो |एक चार के रूप में देखा जाता है न कि एक विशेष प्रतीक के बीच इसे लगाने के लिए []: यानी, split($0, a, "[|]") # मुझे यह '\' से बेहतर लगता है, कुछ मामलों में, विशेष रूप से regexp के कुछ प्रकार के रूप में () पर्ल बनाम जीआरपी बनाम .. अन्य?) हो सकता है "|" वस्तुतः परस्पर और "\" | रेगेक्स विभाजक के रूप में देखा, इसके विपरीत ... ymmv
ओलिवियर

119

स्ट्रिंग को एक सरणी में विभाजित करने के लिए awkहम फ़ंक्शन का उपयोग करते हैं split():

 awk '{split($0, a, ":")}'
 #           ^^  ^  ^^^
 #            |  |   |
 #       string  |   delimiter
 #               |
 #               array to store the pieces

यदि कोई विभाजक नहीं दिया गया है, तो FSवह अंतरिक्ष का उपयोग करता है , जो अंतरिक्ष में चूक करता है:

$ awk '{split($0, a); print a[2]}' <<< "a:b c:d e"
c:d

हम एक विभाजक दे सकते हैं, उदाहरण के लिए ::

$ awk '{split($0, a, ":"); print a[2]}' <<< "a:b c:d e"
b c

जो इसे के माध्यम से स्थापित करने के बराबर है FS:

$ awk -F: '{split($0, a); print a[1]}' <<< "a:b c:d e"
b c

Gawk में आप विभाजक को regexp भी प्रदान कर सकते हैं:

$ awk '{split($0, a, ":*"); print a[2]}' <<< "a:::b c::d e" #note multiple :
b c

और यह भी देखें कि इसके चौथे पैरामीटर का उपयोग करके सीमांकक हर कदम पर क्या था:

$ awk '{split($0, a, ":*", sep); print a[2]; print sep[1]}' <<< "a:::b c::d e"
b c
:::

चलिए GNU awk के मैन पेज को उद्धृत करते हैं :

विभाजन (स्ट्रिंग, सरणी [, फ़ील्ड्स [, सेप्स]])

फूट डालो स्ट्रिंग टुकड़ों में से अलग कर दिया fieldsep और में टुकड़े की दुकान सरणी में और विभाजक तार SEPs सरणी। पहला टुकड़ा में संग्रहीत किया जाता है array[1], दूसरा टुकड़ा अंदर array[2]और आगे। तीसरे तर्क का स्ट्रिंग मान, फ़ील्डेप , एक रेगीक्सप है जिसमें यह वर्णन किया गया है कि स्ट्रिंग को कहाँ विभाजित किया जाए (जितना कि एफएस एक रेगीक्सपी हो सकता है , यह वर्णन करते हुए कि इनपुट रिकॉर्ड को कहाँ विभाजित किया जाए)। यदि फ़ील्डेप को छोड़ दिया जाता है, तो FS का मान उपयोग किया जाता है। split()बनाए गए तत्वों की संख्या लौटाता है। सेप्स एक gawkएक्सटेंशन है, जिसके seps[i]बीच विभाजक स्ट्रिंग हैarray[i]और array[i+1]। यदि फ़ील्ड्स एक एकल स्थान है, तो कोई भी प्रमुख व्हाट्सएप में चला जाता है seps[0]और किसी भी अनुगामी व्हाट्सएप में चला जाता है seps[n], जहां n का रिटर्न मान है split()(अर्थात, सरणी में तत्वों की संख्या)।


सिर्फ उल्लेख करें कि आप गन्न अवेक का उपयोग कर रहे हैं, नियमित रूप से नहीं (जो सेप में विभाजकों को संग्रहीत नहीं करता है] [, और अन्य सीमाएँ हैं)
ओलिवियर डुलैक

17

कृपया और स्पष्ट बताएं! "यह काम नहीं करता है" से आपका क्या मतलब है? सटीक आउटपुट (या त्रुटि संदेश), अपना OS और awk संस्करण पोस्ट करें:

% awk -F\| '{
  for (i = 0; ++i <= NF;)
    print i, $i
  }' <<<'12|23|11'
1 12
2 23
3 11

या, विभाजन का उपयोग कर:

% awk '{
  n = split($0, t, "|")
  for (i = 0; ++i <= n;)
    print i, t[i]
  }' <<<'12|23|11'
1 12
2 23
3 11

संपादित करें: सोलारिस पर आपको 4000 क्षेत्रों को सही ढंग से संसाधित करने के लिए POSIX awk ( / usr / xpg4 / bin / awk ) का उपयोग करने की आवश्यकता होगी ।


for(i = 0या for(i = 1?
PiotrNycz

i = 0, क्योंकि मैं ++ का उपयोग करता हूं (i ++ के बाद नहीं)।
दिमित्रे रादोलोव

3
ठीक है - मैंने इस पर ध्यान नहीं दिया। मेरा मानना ​​है कि अधिक पठनीय होगा for (i = 1; i <= n; ++i)...
PiotrNycz

5

मुझे echo "..." | awk ...समाधान पसंद नहीं है क्योंकि यह अनावश्यक forkऔर execसिस्टम कॉल कहता है।

मैं थोड़ा मोड़ के साथ दिमित्रे के समाधान को पसंद करता हूं

awk -F\| '{print $3 $2 $1}' <<<'12|23|11'

या थोड़ा छोटा संस्करण:

awk -F\| '$0=$3 $2 $1' <<<'12|23|11'

इस मामले में आउटपुट रिकॉर्ड एक साथ रखा जाता है जो एक सच्ची स्थिति है, इसलिए यह प्रिंट हो जाता है।

इस विशिष्ट मामले में stdinपुनर्निर्देशन को एक सेटिंग के साथ बख्शा जा सकता है आंतरिक चर:

awk -v T='12|23|11' 'BEGIN{split(T,a,"|");print a[3] a[2] a[1]}'

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

T='12|23|11';echo -n ${T##*|};T=${T%|*};echo ${T#*|}${T%|*}
T='12|23|11';echo ${T:6}${T:3:2}${T:0:2}

सभी मामलों में परिणाम है

112312

मुझे लगता है कि प्रिंट परिणाम उदाहरण की परवाह किए बिना अंतिम परिणाम awk सरणी चर संदर्भ होना चाहिए था। लेकिन आप अपना अंतिम परिणाम प्रदान करने के लिए वास्तव में आसान बैश मामला चूक गए। T = '12: 23: 11 '; गूंज $ {T //:}
डैनियल लिस्टन

@DanielListon आप सही हैं! धन्यवाद! मुझे नहीं पता था कि अनुगामी / को इस bashअभिव्यक्ति में छोड़ा जा सकता है ...
TrueY

4

दरअसल awkइसमें 'इनपुट फील्ड सेपरेटर वैरिएबल' लिंक नाम का एक फीचर है । यह इसका उपयोग कैसे करना है। यह वास्तव में एक सरणी नहीं है, लेकिन यह आंतरिक $ चर का उपयोग करता है। एक साधारण स्ट्रिंग को विभाजित करने के लिए यह आसान है।

echo "12|23|11" | awk 'BEGIN {FS="|";} { print $1, $2, $3 }'

3
echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'

कार्य करना चाहिए।



1

मज़ाक? :)

कैसा रहेगा echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'

यह मेरा आउटपुट है:

p2> echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
112312

इसलिए मुझे लगता है कि यह सब के बाद काम कर रहा है ..


क्या यह स्ट्रिंग की लंबाई के कारण है? चूंकि, मेरी स्ट्रिंग की लंबाई 4000 है। किसी भी विचार
मोहम्मद सालिह

1

मुझे पता है कि यह एक पुराना सवाल है, लेकिन मुझे लगा कि शायद कोई मेरी चाल पसंद है। खासकर जब से यह समाधान एक विशेष संख्या में वस्तुओं तक सीमित नहीं है।

# Convert to an array
_ITEMS=($(echo "12|23|11" | tr '|' '\n'))

# Output array items
for _ITEM in "${_ITEMS[@]}"; do
  echo "Item: ${_ITEM}"
done

उत्पादन होगा:

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