रिक्त स्थान के साथ 'इन' लूप के लिए पूरी लाइन कैसे पढ़ें


127

मैं forफ़ाइल के लिए लूप चलाने की कोशिश कर रहा हूं और मैं पूरी लाइन प्रदर्शित करना चाहता हूं। लेकिन इसके बजाय केवल अंतिम शब्द प्रदर्शित करना। मुझे पूरी लाइन चाहिए।

for j in `cat ./file_wget_med`

do
echo $j

done

रन के बाद परिणाम:

Found.

यहाँ मेरा डेटा है:

$ cat file_wget_med
2013-09-11 14:27:03 ERROR 404: Not Found.

जवाबों:


177

forजब यह स्पेस, टैब या न्यूलाइन जैसे किसी व्हाट्सएप को देखता है तो लूप बंट जाता है। तो, आपको IFS (आंतरिक क्षेत्र विभाजक) का उपयोग करना चाहिए :

IFS=$'\n'       # make newlines the only separator
for j in $(cat ./file_wget_med)    
do
    echo "$j"
done
# Note: IFS needs to be reset to default!

5
और IFS पर सिंगल कोट्स का ध्यान रखें क्योंकि IFS = $ "\ n" भी "nn" स्ट्रिंग्स को विभाजित करेगा। मैंने पाया कि IFS अधिक जटिल वाक्यविन्यास या कार्यों के उपयोग से अधिक विश्वसनीय है।
erm3nda

23
जाहिरा तौर पर इसे unset IFSबाद में करने की सलाह दी जाती है , ताकि अन्य कमांड इस एक ही शेल में प्रभावित न हों।
बोरिस डैपेन

2
में क्या $मतलब है IFS=$'\n'?
रेन

2
$स्ट्रिंग के अंदर लाइन ब्रेक काम करता है। यह भी local IFS=$'\n'एक फ़ंक्शन के अंदर किया जाना चाहिए ।
एंडी रे

1
@ पता है कि $'...'" ANSI-C Quoting "
αнsнι

82

forडिफ़ॉल्ट रूप से किसी भी व्हाट्सएप (स्पेस, टैब, न्यूलाइन) पर विभाजन विभाजित होता है; एक समय में एक लाइन पर काम करने का सबसे आसान तरीका while readइसके बजाय लूप का उपयोग करना है, जो नईलाइन्स पर विभाजित होता है:

while read i; do echo "$i"; done < ./file_wget_med

मैं उम्मीद करूंगा कि आपकी कमांड प्रति पंक्ति एक शब्द से बाहर निकलेगी (ऐसा तब हुआ जब मैंने इसे अपनी खुद की फ़ाइल के साथ परीक्षण किया)। अगर कुछ और हो रहा है, तो मुझे यकीन नहीं है कि इसका क्या कारण हो सकता है।


7
यह for i in `ls`; do echo $1; doneआउटपुट के लिए एक अच्छा विकल्प भी है , जबकि आउटपुट को कमांड तक ls|while read i; do echo $i; done:। यह वातावरण चर बदलने की आवश्यकता के बिना, रिक्त स्थान के साथ फ़ाइल / फ़ोल्डर नामों पर काम करता है। बहुत अच्छा जवाब।
जिषि

जबकि पहली और आखिरी लाइनों को बहुत संभाल नहीं किया, साथ ही IFS के साथ लूप के लिए नहीं
अनुदान

@ जिशी चूंकि यह मुख्य रूप से प्रदर्शन के लिए डिज़ाइन किया गया है, और टर्मिनल-विंडो के आकार के लिए उत्तरदायी है और इस तरह, (पाइप लाइन) के lsसाथ उपयोग के लिए सुरक्षित नहीं माना जाता है |findइस उद्देश्य के लिए सुरक्षित होने के अलावा और अधिक लचीला है।
सेलेडमनीडे

3
यह एक महान जवाब है, मैंने इसे मैक ओएसएक्स पर विकसित होने वाले आईओएस ऐप के लिए पीएलआईएसटी प्रविष्टियों में एक सूची को चालू करने के लिए इस्तेमाल किया था। मैं clipboad का उपयोग कर पाइप द्वारा फ़ाइल इनपुट प्रतिस्थापित pbpaste ->pbpaste | while read t; do echo "<string>$t</string>"; done
बिग रिच

3
ls -1|एक-प्रति-पंक्ति
बिना लाइसेंस वाले

19
#!/bin/bash
files=`find <subdir> -name '*'`
while read -r fname; do
    echo $fname
done <<< "$files"

सत्यापित काम कर रहा है, न कि एक लाइनर जो आप चाहते हैं, लेकिन यह इतनी भव्यता से करना संभव नहीं है।


1
यहाँ एक स्ट्रिंग! अन्य सभी समाधानों का सबसे सुरुचिपूर्ण IMO
एलिरन मलका

5

यहां मिचेल करी के जवाब का थोड़ा विस्तार है, क्योंकि मुझे साइड इफेक्ट्स के छोटे दायरे के कारण पसंद है, जो एक चर सेट करने से बचता है:

#!/bin/bash
while read -r fname; do
    echo $fname
done <<< "`find <subdir>`"

1
आप निकाल सकते हैं -name '*'और यह वही होगा, नहीं?
वेजेंड्रिया

1

मैं इसे इस तरह लिखूंगा:

cat ./file_wget_med | while read -r j
do
    echo $j
done

चूंकि इसे मूल स्क्रिप्ट में कम से कम बदलाव की आवश्यकता होती है (समाधान का उपयोग करने के अलावा IFS, लेकिन यह bashन केवल इस लूप नियंत्रण कथन के लिए व्यवहार को संशोधित करता है)।


1
पाइप और catयहां अनावश्यक हैं। whileलूप पुनर्निर्देशन को ठीक मानता है, यही कारण है कि यह आमतौर पर लिखा जाता हैwhile IFS= read -r line; do...done < input.txt
सर्जियो कोलोडियाज़नी

0

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

#!/bin/bash

mapfile -t < file.txt

for line in "${MAPFILE[@]}"; do
    echo $line
done

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

उदाहरण:

#!/bin/bash

a=0
printf %s\\n {0..5} | while read; do
  ((a++))
done
echo $a # 'a' will always be 0.

(बेहतर समाधान):

#!/bin/bash

b=0
while read; do
  ((b++))
done < <(printf %s\\n {0..5})

echo $b # 'b' equal to 6 (works as expected).

-1

डैंडलफ एक कार्यात्मक समाधान के करीब पहुंच गया, लेकिन किसी find ~/.gdfuse -name '*'को भी चर के लिए अज्ञात मात्रा में इनपुट (यानी ) के परिणाम को निर्दिष्ट करने की कोशिश नहीं करनी चाहिए ! या, कम से कम एक सरणी चर के माध्यम से ऐसा काम करने की कोशिश कर रहा है; यदि आप बहुत आलसी होने पर जोर देते हैं! तो, यहाँ खतरनाक पैंतरेबाज़ी के बिना Dandalf समाधान किया गया है; और सभी एक पंक्ति में

while read -r fname; do
  echo $fname;
done <<< `find ~/.gdfuse -name '*'

अरे @odoncaoa, मैंने डबल कोट्स के बिना खोज कमांड को करने की कोशिश की, लेकिन यह सभी परिणामों को एक पंक्ति के रूप में प्रकट करता है। मैं इस आदेश और शामिल खतरों के साथ "अज्ञात मात्रा में इनपुट" के बारे में उलझन में हूं। क्या आप खतरों का एक उदाहरण प्रदान कर सकते हैं और वे सैद्धांतिक रूप से कैसे हो सकते हैं? मैं गंभीरता से इसके बारे में आलसी होने की इच्छा नहीं करता, मैं अन्य प्रोग्रामिंग भाषाओं में बस अधिक आरामदायक हूं।
डंडालफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.