अल्पविराम से अलग शेल चर के माध्यम से लूप


109

मान लीजिए कि मेरे पास नीचे की तरह एक यूनिक्स शैल चर है

variable=abc,def,ghij

मैं लूप का उपयोग करके सभी मानों ( और abc, ) को निकालना चाहता हूं और प्रत्येक मान को एक प्रक्रिया में पास करता हूं ।defghij

स्क्रिप्ट को अल्पविराम से अलग मानों की मनमानी संख्या निकालने की अनुमति देनी चाहिए $variable


वास्तव में आप इससे अधिक क्या करना चाहते हैं?
एसएमए

1
मैं एक प्रक्रिया के तर्क के रूप में क्षेत्र के प्रत्येक (अबेक कहना) को पारित करना चाहता हूं।
रामनाथन के

जवाबों:


125

आप अपने चर के माध्यम से गतिशील रूप से पार करने के लिए निम्न स्क्रिप्ट का उपयोग कर सकते हैं, चाहे वह कितने ही क्षेत्रों में हो, जब तक कि यह केवल अल्पविराम से अलग हो।

variable=abc,def,ghij
for i in $(echo $variable | sed "s/,/ /g")
do
    # call your procedure/other scripts here below
    echo "$i"
done

लूप के लिए और echo "$i"उसके बीच के ऊपर कॉल के बजाय , आप अपनी प्रक्रिया को लागू कर सकते हैं ।dodoneproc "$i"


अद्यतन : उपरोक्त स्निपेट कार्य करता है यदि चर के मान में रिक्त स्थान नहीं हैं। यदि आपके पास ऐसी आवश्यकता है, तो कृपया एक समाधान का उपयोग करें जो बदल सकता है IFSऔर फिर आपके चर को पार्स कर सकता है।


उम्मीद है की यह मदद करेगा।


8
यह काम नहीं करता है अगर $variableइसमें व्हॉट्सएप है, उदाहरण के लिए variable=a b,c,d= 3 के बजाय 3 लाइन (a (b | c | d) प्रिंट करता है) (ab | c | d)
Dan

और साथ ही इसमें ** "value ** जैसे नए उद्धरण जोड़े जा रहे हैं । क्या आप इसे अपडेट कर सकते हैं अगर वहाँ कोई रेगेक्स है कि ..
gks

136

IFS के साथ खिलवाड़
नहीं करना बाहरी आदेश को नहीं कहना

variable=abc,def,ghij
for i in ${variable//,/ }
do
    # call your procedure/other scripts here below
    echo "$i"
done

बैश स्ट्रिंग हेरफेर का उपयोग http://www.tldp.org/LDP/abs/html/string-manipulation.html


3
इसके बारे में अच्छी बात यह है कि आप अलग-अलग सीमांकक का उपयोग करके कई छोरों को घोंसला कर सकते हैं। अच्छा सुझाव!
ब्रैड पार्क

5
के साथ गड़बड़ से बचने के लिए अच्छा टिप IFS!
लाईमोनिन्जस

13
छोटी चेतावनी - यदि किसी भी मान में $iरिक्त स्थान हैं, तो वे विभाजित हो जाएंगे (और इसका कारण यह हो सकता है कि यह अल्पविराम से अलग हो गया है क्योंकि अंतरिक्ष से अलग हो गया है)
Toby Speight

4
यदि पिछले फ़ंक्शन ने IFS सेटिंग को बदल दिया है, तो यह काम नहीं करता है ... इसे इसे बदलें:for i in ${variable//,/$IFS} do; echo "$i"; done
Joep

2
जब मैं इस दृष्टिकोण की कोशिश करता हूं तो मुझे त्रुटि संदेश "खराब प्रतिस्थापन" मिलता है।
खोया Crotchet

55

यदि आप एक अलग क्षेत्र विभाजक सेट करते हैं, तो आप सीधे forलूप का उपयोग कर सकते हैं :

IFS=","
for v in $variable
do
   # things with "$v" ...
done

आप किसी सरणी में मान भी संग्रहीत कर सकते हैं और फिर इसके माध्यम से लूप कर सकते हैं जैसा कि संकेत दिया गया है कि मैं बैश में एक सीमांकक पर एक स्ट्रिंग कैसे विभाजित करूं? :

IFS=, read -ra values <<< "$variable"
for v in "${values[@]}"
do
   # things with "$v"
done

परीक्षा

$ variable="abc,def,ghij"
$ IFS=","
$ for v in $variable
> do
> echo "var is $v"
> done
var is abc
var is def
var is ghij

आप इस समाधान में एक व्यापक दृष्टिकोण पा सकते हैं कि कैसे एक अल्पविराम से अलग की गई सूची के माध्यम से पुनरावृत्ति करें और प्रत्येक प्रविष्टि के लिए एक कमांड निष्पादित करें

दूसरे दृष्टिकोण पर उदाहरण:

$ IFS=, read -ra vals <<< "abc,def,ghij"
$ printf "%s\n" "${vals[@]}"
abc
def
ghij
$ for v in "${vals[@]}"; do echo "$v --"; done
abc --
def --
ghij --

इसके अलावा stackoverflow.com/questions/918886/… :-) सभी को शुभकामनाएँ देखें ।
शेल्टर

हां! मैंने इसके बारे में भी सोचा, केवल यह कि इसके बाद चरणों की आवश्यकता है: एक whileसरणी में पढ़ने के लिए और परिणामों के माध्यम से लूप करने के लिए एक और।
फेडोरक्वी 'एसओ

3
मुझे खुश करता है जब कोई वास्तव में जानता है कि शेल का उपयोग कैसे करना है, बल्कि पाइप से एक साथ बन्नीटल्स का एक गुच्छा।
पीटर एफटी

क्या आपको IFSपहले जो कुछ भी था उसे वापस सेट करना होगा?
1

1
@fedorqui यह किया! यही एकमात्र चर है जिसके माध्यम से मैं पाश करना चाहता था और इसने मेरी यामल फ़ाइल को पढ़ने में आसान बना दिया (एक लम्बी पर्यावरण चर के बजाय इसमें पंक्तियों का एक गुच्छा है)
गामागेम

5
#/bin/bash   
TESTSTR="abc,def,ghij"

for i in $(echo $TESTSTR | tr ',' '\n')
do
echo $i
done

मैं sed के बजाय tr का उपयोग करना पसंद करता हूं, becouse sed को कुछ मामलों में \ r \ n जैसे विशेष वर्णों की समस्या है।

अन्य समाधान IFS को कुछ विभाजक में सेट करना है


1

यहाँ एक वैकल्पिक tr आधारित समाधान है जो एक-लाइनर के रूप में व्यक्त की गई इको का उपयोग नहीं करता है।

for v in $(tr ',' '\n' <<< "$var") ; do something_with "$v" ; done

यह गूंज के बिना tidier लगता है, लेकिन यह सिर्फ मेरी व्यक्तिगत पसंद है।


0

इसको आजमाओ।

#/bin/bash   
testpid="abc,def,ghij" 
count=`echo $testpid | grep -o ',' | wc -l` # this is not a good way
count=`expr $count + 1` 
while [ $count -gt 0 ]  ; do
     echo $testpid | cut -d ',' -f $i
     count=`expr $count - 1 `
done

लेकिन क्या होगा अगर मैं चर टेस्टपीड में फ़ील्ड की संख्या के बारे में सुनिश्चित नहीं हूं?
रामनाथन के

इसके अलावा, मुझे एक प्रक्रिया के तर्क के रूप में उपरोक्त चर के प्रत्येक दायर को पारित करने की आवश्यकता है। और मैं यह करना चाहता हूं जब तक कि चर की लंबाई शून्य न हो जाए। (यानी, सभी क्षेत्रों को प्रसंस्करण के लिए प्रक्रिया के लिए एक बार पारित किया जाना चाहिए)
रामानाथन के

मैं इस प्रक्रिया के बारे में नहीं जानता। इस लिंक से आप खेतों की गिनती प्राप्त कर सकते हैं। http://stackoverflow.com/questions/8629330/unix-count-of-columns-in-file। उसके बाद उस लूप को लूप में रखें। आप वह प्राप्त कर सकते हैं।
कार्तिकेयन।

यह मुझे लगता है कि एक फ़ाइल से क्षेत्रों की गणना करने के लिए है। अगर मुझे चर में खेतों को गिनने की आवश्यकता हो तो (मान लीजिए कि परिक्षण testpid = abc, def, ghij है)
रामनाथन K

चर को प्रतिध्वनित करें और आउटपुट को awk पर पाइप करें। वरना मेरा अपडेटेड जवाब देखिए। हो सकता है यह उपयोगी हो।
कार्तिकेयन।

0

एक और समाधान IFS का उपयोग नहीं कर रहा है और अभी भी रिक्त स्थान को संरक्षित कर रहा है:

$ var="a bc,def,ghij"
$ while read line; do echo line="$line"; done < <(echo "$var" | tr ',' '\n')
line=a bc
line=def
line=ghij

यह बाश में सही ढंग से काम करता है, हालांकि zsh रिक्त स्थान को निगलता है।
13 सितंबर

0

यहां मेरा शुद्ध बैश समाधान है जो IFS को नहीं बदलता है, और एक कस्टम रेगेक्स सीमांकक में ले जा सकता है।

loop_custom_delimited() {
    local list=$1
    local delimiter=$2
    local item
    if [[ $delimiter != ' ' ]]; then
        list=$(echo $list | sed 's/ /'`echo -e "\010"`'/g' | sed -E "s/$delimiter/ /g")
    fi
    for item in $list; do
        item=$(echo $item | sed 's/'`echo -e "\010"`'/ /g')
        echo "$item"
    done
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.