2012-11-20 21 views
20

मैं निम्नलिखित जानना चाहता हूं;एक बाश सरणी को एक सीमित स्ट्रिंग में परिवर्तित करना

  1. क्यों दिया गया गैर-कामकाजी उदाहरण काम नहीं करता है।
  2. यदि काम करने वाले उदाहरण में दिए गए किसी भी अन्य क्लीनर विधियां हैं।

बेकार उदाहरण

> ids=(1 2 3 4);echo ${ids[*]// /|} 
1 2 3 4 
> ids=(1 2 3 4);echo ${${ids[*]}// /|} 
-bash: ${${ids[*]}// /|}: bad substitution 
> ids=(1 2 3 4);echo ${"${ids[*]}"// /|} 
-bash: ${"${ids[*]}"// /|}: bad substitution 

कार्य उदाहरण

> ids=(1 2 3 4);id="${ids[@]}";echo ${id// /|} 
1|2|3|4 
> ids=(1 2 3 4); lst=$(IFS='|'; echo "${ids[*]}"); echo $lst 
1|2|3|4 

संदर्भ में, सीमांकित स्ट्रिंग आगे पार्स के लिए एक sed आदेश में इस्तेमाल किया जाएगा।

+1

'$ {$ {आईडी [*]} ///|}' एक सिंटैक्स त्रुटि है, कि सब। डुनो जो आप यहां हासिल करने की कोशिश कर रहे हैं। –

+0

1 हॉप में वेरिएबल प्रतिस्थापन प्राप्त करने का प्रयास कर रहा है, यह कभी भी काम नहीं करेगा ... – koola

उत्तर

23
# REVISION: 2017-03-14 
# Use of read and other bash specific features (bashisms) 

कोष्ठकों एक सरणी, नहीं परिसीमित करने के लिए एक स्ट्रिंग उपयोग किया जाता है क्योंकि:

ids="1 2 3 4";echo ${ids// /|} 
1|2|3|4 

कुछ नमूने: दो तार के साथ $ids से पॉप्युलेट: a b और c d

ids=("a b" "c d") 

echo ${ids[*]// /|} 
a|b c|d 

IFS='|';echo "${ids[*]}";IFS=$' \t\n' 
a b|c d 

... और अंत में:

IFS='|';echo "${ids[*]// /|}";IFS=$' \t\n' 
a|b|c|d 

कहाँ सरणी, इकट्ठे है $IFS के 1 चार से अलग कर दिया है, लेकिन अंतरिक्ष के साथ सरणी के प्रत्येक तत्व में | द्वारा बदल दिया।

जब आप ऐसा करेंगे:

id="${ids[@]}" 

आप स्थानांतरित स्ट्रिंग के प्रकार स्ट्रिंग एक नया वेरिएबल को सरणीids के विलय से निर्माण एक रिक्ति से।

नोट: जब "${ids[@]}" एक अंतरिक्ष से अलग किए स्ट्रिंग दे, "${ids[*]}" (एक स्टार * के बजाय साथ हस्ताक्षर @ पर) एक स्ट्रिंग $IFS की पहला वर्ण द्वारा अलग से प्रस्तुत करना होगा।

क्या man bash का कहना है:

man -Len -Pcol\ -b bash | sed -ne '/^ *IFS /{N;N;p;q}' 
    IFS The Internal Field Separator that is used for word splitting 
      after expansion and to split lines into words with the read 
      builtin command. The default value is ``<space><tab><newline>''. 

$IFS के साथ खेलना:

set | grep ^IFS= 
IFS=$' \t\n' 

declare -p IFS 
declare -- IFS=" 
" 
printf "%q\n" "$IFS" 
$' \t\n' 

सचमुच space, tabulation और (यानीline-feed। तो, जबकि पहला चरित्र एक जगह है। * का उपयोग @ जैसा ही होगा।

लेकिन:

{ 

# OIFS="$IFS" 
    # IFS=$': \t\n' 
    # unset array 
    # declare -a array=($(echo root:x:0:0:root:/root:/bin/bash)) 

IFS=: read -a array < <(echo root:x:0:0:root:/root:/bin/bash) 

    echo 1 "${array[@]}" 
    echo 2 "${array[*]}" 
    OIFS="$IFS" IFS=: 
    echo 3 "${array[@]}" 
    echo 4 "${array[*]}" 
    IFS="$OIFS" 
} 
1 root x 0 0 root /root /bin/bash 
2 root x 0 0 root /root /bin/bash 
3 root x 0 0 root /root /bin/bash 
4 root:x:0:0:root:/root:/bin/bash 

नोट: लाइन IFS=: read -a array < <(...)का उपयोग करेगाविभाजक के रूप में, $IFS को स्थायी रूप से सेट किए बिना। ऐसा इसलिए है क्योंकि आउटपुट लाइन #2 विभाजक के रूप में वर्तमान रिक्त स्थान।

+0

तो यह दोनों प्रकार की टाइपिंग और परिवर्तनीय प्रतिस्थापन त्रुटि दोनों को {{प्रकार की स्ट्रिंग की अपेक्षा है लेकिन न तो प्राप्त करता है। विस्तृत स्पष्टीकरण के लिए धन्यवाद। – koola

+0

कोई स्ट्रिंग असाइनमेंट को भी छोड़ सकता है और फिर भी एक सरणी को एक सीमांकित स्ट्रिंग * में एक मनमानी डिलीमीटर * के साथ परिवर्तित कर सकता है, अनिवार्य रूप से एक सिंगल कैरेक्टर नहीं, 'printf'% smyDelim '$ {array [@]} "'। डेलीमीटर 'myDelim' का अंतिम उदाहरण' sed -e '/ myDelim $ //' में पाइप करके हटाया जा सकता है, लेकिन यह बोझिल है। बेहतर विचार? –

+1

@ जोनाथनवाई। यदि ऐसा है, तो 'printf -v myVar'% smyDelim '' $ {array [@]} "का उपयोग करें; myVar = "$ {myVar% myDelim}" 'फोर्क के बजाय' sed' –

9

आपका पहला प्रश्न पहले से ही एफ। हॉरी के जवाब में संबोधित किया गया है। यहाँ एक सरणी के तत्वों के शामिल होने के लिए विहित तरीका है:

ids=(1 2 3 4) 
IFS=\| eval 'lst="${ids[*]}"' 

कुछ लोगों को रोना होगा जोर है कि eval बुराई है, फिर भी यह, यहाँ पूरी तरह से सुरक्षित है एकल उद्धरण के लिए धन्यवाद। इसमें केवल फायदे हैं: कोई सबहेल नहीं हैं, IFS वैश्विक स्तर पर संशोधित नहीं है, यह पीछे की नईलाइनों को ट्रिम नहीं करेगा, और यह बहुत आसान है।

0

आप किसी भी बाहरी कमांड या आईएफएस से निपटने के लिए की आवश्यकता के बिना भी printf उपयोग कर सकते हैं,:

ids=(1 2 3 4) 
printf -v ids_d '|%s' "${ids[@]}" # yields "|1|2|3|4" 
ids_d=${ids_d:1}     # remove the leading '|'