उन आश्चर्यजनक रूप से लगातार मामलों में जहां आपको वास्तव में क्या करने की आवश्यकता है, सभी गैर-रिक्त लाइनों को कुछ फ़ैशन में एक चर के अंदर संसाधित करना है (उन्हें गिनना भी शामिल है), आप IFS को केवल एक नई रेखा पर सेट कर सकते हैं और फिर शेल के शब्द विभाजन तंत्र का उपयोग कर सकते हैं गैर-खाली लाइनों के अलावा।
उदाहरण के लिए, यहां एक छोटा शेल फ़ंक्शन है जो सभी आपूर्ति किए गए तर्कों के अंदर गैर-खाली लाइनों को योग करता है:
lines() (
IFS='
'
set -f #disable pathname expansion
set -- $*
echo $#
)
कोष्ठक के बजाय कोष्ठक का उपयोग यहां फ़ंक्शन बॉडी के लिए कंपाउंड कमांड बनाने के लिए किया जाता है। यह फ़ंक्शन को एक सब-टाइम में निष्पादित करता है ताकि यह हर कॉल पर बाहरी दुनिया के IFS चर और pathname विस्तार सेटिंग को प्रदूषित न करे।
यदि आप गैर-खाली लाइनों पर पुनरावृति करना चाहते हैं, तो आप इसे इसी तरह कर सकते हैं:
IFS='
'
set -f
for line in $lines
do
printf '[%s]\n' $line
done
इस तरह से मैनिप्युलेटिंग IFS एक अक्सर-अनदेखी तकनीक है, पार्सिंग पाथनेम्स जैसी चीजों को करने के लिए भी आसान है जिसमें टैब-सीमांकित स्तंभ इनपुट से रिक्त स्थान हो सकते हैं। हालाँकि, आपको इस बात से अवगत होना चाहिए कि स्पेस-टैब-न्यूलाइन की आईएफएस की डिफ़ॉल्ट सेटिंग में आमतौर पर शामिल किए गए स्पेस कैरेक्टर को जानबूझकर हटाना उन स्थानों में शब्द विभाजन को अक्षम कर सकता है जहां आप इसे देखने की उम्मीद करेंगे।
उदाहरण के लिए, यदि आप किसी चीज़ के लिए एक जटिल कमांड लाइन बनाने के लिए चर का उपयोग कर रहे हैं, तो आप केवल तभी ffmpeg
शामिल करना चाह सकते हैं -vf scale=$scale
जब चर scale
को कुछ गैर-रिक्त पर सेट किया जाए। आम तौर पर आप के साथ इस लक्ष्य को हासिल कर सकता है ${scale:+-vf scale=$scale}
, लेकिन अगर आईएफएस समय इस पैरामीटर विस्तार किया जाता है पर अपने सामान्य अंतरिक्ष चरित्र शामिल नहीं है, अंतरिक्ष के बीच -vf
और scale=
एक शब्द विभाजक के रूप में उपयोग नहीं किया जाएगा और ffmpeg
सभी के पारित हो जाएगा -vf scale=$scale
एक भी तर्क के रूप में, जिसे यह समझ नहीं आएगा।
इसे ठीक करने के लिए, आपको यह सुनिश्चित करने की आवश्यकता होगी कि ${scale}
विस्तार करने से पहले IFS को सामान्य रूप से सेट किया गया था , या दो विस्तार करें ${scale:+-vf} ${scale:+scale=$scale}
:। शब्द को विभाजित करना जो शेल कमांड लाइनों के प्रारंभिक पार्सिंग की प्रक्रिया में करता है, जैसा कि उन कमांड लाइनों के प्रसंस्करण के विस्तार चरण के दौरान विभाजन के विपरीत होता है, IFS पर निर्भर नहीं करता है।
कुछ और जो आपके लायक हो सकता है अगर आप इस तरह का काम करने जा रहे हैं तो सिर्फ एक टैब और एक नई लाइन रखने के लिए दो वैश्विक शेल वैरिएबल बनाए जाएंगे:
t=' '
n='
'
इस तरह आप बस शामिल कर सकते हैं $t
और $n
विस्तार जहां टैब और नई-पंक्तियों की जरूरत है, न कि कचरा से उद्धृत सफेद स्थान के साथ अपने सभी कोड में। यदि आप इसके बजाय POSIX खोल में पूरी तरह से उद्धृत व्हाट्सएप से बचते हैं, जिसमें ऐसा करने के लिए कोई अन्य तंत्र नहीं है, तो printf
मदद कर सकता है, हालांकि आपको कमांड विस्तारों में नई रूपरेखाओं को हटाने के लिए काम करने के लिए थोड़ी सी फ़िदालिंग की आवश्यकता है:
nt=$(printf '\n\t')
n=${nt%?}
t=${nt#?}
कभी-कभी IFS की स्थापना करना जैसे कि यह एक प्रति-कमांड वातावरण चर अच्छा काम करता है। उदाहरण के लिए, यहाँ एक लूप है जो एक पथनाम को पढ़ता है जिसमें रिक्त स्थान शामिल है और टैब-सीमांकित इनपुट फ़ाइल की प्रत्येक पंक्ति से स्केलिंग कारक है:
while IFS=$t read -r path scale
do
ffmpeg -i "$path" ${scale:+-vf scale=$scale} "${path%.*}.out.mkv"
done <recode-queue.txt
इस मामले में read
बिलिन IFS को सिर्फ एक टैब पर सेट करता है, इसलिए यह रिक्त स्थान पर पढ़ी गई इनपुट लाइन को विभाजित नहीं करेगा। लेकिन IFS=$t set -- $lines
काम नहीं करता है: शेल का विस्तार होता है $lines
क्योंकि यह कमांड निष्पादित करने से पहलेset
बिलिन के तर्कों का निर्माण करता है , इसलिए आईएफएस की अस्थायी सेटिंग इस तरह से होती है जो केवल बिलिन के निष्पादन के दौरान ही लागू होती है। यही कारण है कि कोड स्निपेट मैंने सभी सेट IFS के ऊपर एक अलग चरण में दिए हैं, और उन्हें इसे संरक्षित करने के मुद्दे से क्यों निपटना है।
wc -l
मूल के बिल्कुल समतुल्य है: (भले ही खाली हो)<<<$foo
के मूल्य में एक नई रेखा जोड़ता है । मैं अपने जवाब में समझाता हूं कि ऐसा क्यों नहीं हो सकता था जो वह चाहते थे, लेकिन यह वही है जो पूछा गया था।$foo
$foo