2017-01-23 4 views
8

में आईएफएस शब्द विभाजन को नियंत्रित करने के लिए कैसे मैं यह पता लगाने की कोशिश कर रहा हूं कि आईएफएस बैश में शब्द विभाजन को कैसे प्रभावित करता है। व्यवहार संदर्भ ऐसे तरीके से निर्भर है जो शब्द विभाजन के अंतर्ज्ञान से मेल नहीं खाता है।बैश

सामान्य विचार काफी सरल लगता है। बैश मैन पेज से उद्धरण:

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

यह आईएफएस वैरिएबल को ',' पर सेट करके और अल्पविराम से अलग तर्क सूची के साथ एक खोल फ़ंक्शन का आविष्कार करके उदाहरण के लिए आसानी से सत्यापित किया जा सकता है।

echo_n() { 
    echo Num args: $#, Args: "[email protected]" 
} 
(IFS=',' 
    args=foo,bar,baz 
    echo_n $args 
) 

उम्मीद तीन अलग बहस में इस परिणाम echo_n को

Num args: 3, Args: foo bar baz 

अल्पविराम पृथक सूची के साथ सीधे echo_n लागू के रूप में विफल रहता है, क्योंकि कोई विस्तार शुरू हो रहा है। यहां

IFS=, echo_n foo,bar,baz 

परिणाम

Num args: 1, Args: foo,bar,baz 

ऊपर में चीजों को नहीं बल्कि पीला पड़ लगते हैं, लेकिन मैं उनके आसपास मेरे सिर लपेटो कर सकते हैं। जब हम तस्वीर में लूप के लिए जोड़ना शुरू करते हैं, तो चीजें बालों वाली होती हैं।

(IFS=,; for i in foo,bar,baz ; do echo_n $i; done) 

परिणाम

Num args: 3, Args: foo bar baz 

जो पाश के लिए करने के उद्देश्य धरा में।

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

Num args: 1, Args: foo 
Num args: 1, Args: bar 
Num args: 1, Args: baz 

में

(IFS=,; for i in ${NO_VAR:-foo,bar,baz} ; do echo_n $i; done) 

परिणाम (चाल एक डिफ़ॉल्ट मान के साथ एक अपरिभाषित चर NO_VAR का मूल्यांकन करने में होते हैं।)

एक और इसी तरह की चाल, आदेश प्रतिस्थापन पर निर्भर:

उदाहरण के लिए
(IFS=,; for i in $(echo foo,bar,baz) ; do echo_n $i; done) 

तो यहां सवाल है: अनुशंसित, बेवकूफ तरीका टी क्या है o उस संदर्भ को नियंत्रित करें जहां आईएफएस शब्द विभाजन किया जाता है?

उत्तर

5

यह क्यों निम्नलिखित में विफल रहता है महसूस करने के लिए महत्वपूर्ण है:

$ IFS=, echo_n foo,bar,baz 
Num args: 1, Args: foo,bar,baz 

IFS करने के लिए पूर्व आदेश काम ही लागू होता है अंदर echo_n; foo,bar,baz, पर विभाजित नहीं है क्योंकि इस कमांड लाइन (या इसकी कमी) पर कोई शब्द-विभाजन echo_n रन से पहले होता है। एक एकल पुनरावृत्ति में

(IFS=,; for i in foo,bar,baz ; do echo_n $i; done) 

परिणाम क्योंकि IFS केवल विस्तार के परिणाम विभाजित करने के लिए प्रयोग किया जाता है (और read से, नीचे देखें) शाब्दिक तार, नहीं। शेल द्वारा किए गए शब्द-विभाजन को पहली बार कमांड लाइन को पार्स करने के लिए प्रभावी रूप से हार्डस्पेस पर विभाजित करने के लिए हार्ड-कोड किया जाता है।


यह पूरी तरह स्पष्ट आप क्या हासिल करना चाहते हैं नहीं है, लेकिन अंगूठे का एक अच्छा नियम है कि अगर आप IFS का मूल्य विश्व स्तर पर सेट कर रहे हैं, तो आप कुछ गलत (या कम से कम suboptimally) कर रहे हैं।

  1. IFS=, read -r a b c कई में अल्पविराम का युक्त (यहाँ, 3) टुकड़े एक पंक्ति विभाजित करने के लिए: केवल दो स्थितियों में, जहां मैं उपयोगी IFS संशोधित याद कर सकते हैं। IFS में परिवर्तन read पर स्थानीय है; जो भी स्ट्रिंग इसे पढ़ता है वह पढ़ा जाता है, और आंतरिक रूप सेread द्वारा विभाजित किया जाता है।

  2. foo=$(IFS=.; echo "${foo[*]}") एक सरणी के तत्वों को एक स्ट्रिंग में . के साथ डिलीमीटर के रूप में जोड़ने के लिए। ध्यान दें कि यह IFS पर वैश्विक परिवर्तन है, लेकिन केवल एक वैश्विक दायरे में जो कमांड प्रतिस्थापन पूरा होने के बाद गायब हो जाता है।

अपने for पाश उदाहरण के लिए संबंधित, कभी भी आप एक हार्ड-कोडेड सूची के अलावा कुछ (जो एक सरणी का विस्तार शामिल है), तो आप शायद read के बजाय साथ एक while पाश का उपयोग करना चाहते से अधिक पुनरावृति करना चाहते हैं एक for पाश, Bash FAQ 001 के अनुसार।

उदाहरण के लिए यहाँ for पाश ले लो,:

(IFS=,; for i in $(echo foo,bar,baz) ; do echo_n $i; done) 

मैं बजाय एक सरणी में इसे विभाजित हैं पहले तो for साथ पुनरावृति:

data="foo,bar,baz" 
IFS=, read -r -a items <<< "$data" 
for i in "${data[@]}"; do 
    echo_n "$i" 
done