एक पंक्ति-उन्मुख फ़ाइल पढ़ें जो एक नई पंक्ति के साथ समाप्त नहीं हो सकती है


11

मेरे पास एक फ़ाइल है, /tmp/urlFileजहां प्रत्येक पंक्ति एक यूआरएल का प्रतिनिधित्व करती है। मैं इस प्रकार से फ़ाइल से पढ़ने की कोशिश कर रहा हूँ:

cat "/tmp/urlFile" | while read url
do
    echo $url
done

यदि अंतिम पंक्ति किसी नई पंक्ति वर्ण के साथ समाप्त नहीं होती है, तो वह पंक्ति पढ़ी नहीं जाएगी। मैं सोच रहा था कि क्यों?

क्या सभी लाइनों को पढ़ना संभव है, भले ही वे एक नई रेखा के साथ समाप्त हो जाएं या नहीं?



2
Hah @ Stéphane मुझे वहां का TBD पसंद है; ;-)
स्टीफन किट

2
यदि लापता है तो अनुगामी न्यूलाइन जोड़ने का दूसरा तरीका; awk 1 /tmp/urlFile.. तोawk 1 /tmp/urlFile | while ...
मुरु

@ मरमू, यह किसी अन्य की तुलना में यहां बेहतर उत्तर है।
वाइल्डकार्ड

1
जब से आप पूछ रहे हैं कि यह क्यों नहीं पढ़ा है: stackoverflow.com/a/729795/1968
कोनराड रूडोल्फ

जवाबों:


13

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

while IFS= read -r url || [ -n "$url" ]; do
  printf '%s\n' "$url"
done < url.list

(प्रभावी रूप से, वह लूप पिछली (गैर-) पंक्ति पर अनुपलब्ध न्यूलाइन को वापस जोड़ता है)।

यह सभी देखें:


धन्यवाद। मैं लिंक किए गए लेखों को पढ़ता हूं, और शायद मुझे कुछ याद आता है, क्यों "लूप पिछले (गैर-) लाइन पर लापता नईलाइन को वापस जोड़ता है"?
टिम

1
@Tim स्टीफन का क्या मतलब है, यह आउटपुट में लापता न्यूलाइन को वापस जोड़ता है क्योंकि printfयहां सभी कॉल हैं \n
सर्गी कोलोडियाज़नी

6

इस भाग के साथ हल किया जा रहा है readarray -t:

readarray -t urls "/tmp/urlFile"
for url in "${urls[@]}"; do
    printf '%s\n' "$url"
done

ध्यान दें कि जब यह यथोचित आकार की फ़ाइलों के लिए काम करता है, तो यह समाधान बहुत बड़ी फ़ाइलों के साथ एक संभावित नई समस्या का परिचय देता है - यह पहली बार फ़ाइल को एक सरणी में पढ़ता है जिसके माध्यम से पुनरावृत्त होना चाहिए। बहुत बड़ी फ़ाइलों के लिए यह समय और स्मृति-उपभोग दोनों हो सकता है, संभवतः विफलता के बिंदु तक।


धन्यवाद। कौन सा हिस्सा हल करता है और कौन सा नहीं?
टिम

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

1
@DopeGhoti यह अच्छी जानकारी है - क्या मैं आपको सुझाव दे सकता हूं कि आप इसे सीधे उत्तर में जोड़ दें?
RJHunter

था जवाब में इतना संशोधन किया गया है।
डोपघोटी

5

द्वारा परिभाषा , एक पाठ फ़ाइल लाइनों की एक अनुक्रम के होते हैं। एक पंक्ति एक नई पंक्ति वर्ण के साथ समाप्त होती है। इस प्रकार एक टेक्स्ट फ़ाइल एक नए वर्ण के साथ समाप्त होती है, जब तक कि वह खाली न हो।

readBuiltin केवल पाठ फ़ाइलों को पढ़ने के लिए है। आप एक पाठ फ़ाइल पास नहीं कर रहे हैं, इसलिए आप इसे मूल रूप से काम करने की उम्मीद नहीं कर सकते। शेल सभी पंक्तियों को पढ़ता है - यह जो लंघन है वह अंतिम पंक्ति के बाद के अतिरिक्त वर्ण हैं।

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

{ cat "/tmp/urlFile"; echo; } | 

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

{ <"/tmp/urlFile" tr -d '\r'; echo; } | 

मामले में इनपुट फ़ाइल अच्छी तरह से बनाई गई है और एक नई echoरेखा के साथ समाप्त होती है, एक अतिरिक्त रिक्त पंक्ति को जोड़ता है। चूंकि URL रिक्त नहीं हो सकते हैं, बस रिक्त लाइनों को अनदेखा करें।

ध्यान दें कि readसीधी तरह से लाइनों को न पढ़ें। यह व्हाट्सएप के अग्रणी और अनुगामी को नजरअंदाज करता है, जो शायद एक URL के लिए वांछनीय है। यह एक पंक्ति के अंत में बैकस्लैश को एक एस्केप कैरेक्टर के रूप में मानता है, जिससे अगली लाइन पहले माइनस बैकस्लैश-न्यूलाइन अनुक्रम के साथ जुड़ जाती है, जो निश्चित रूप से वांछनीय नहीं है। इसलिए आपको -rविकल्प पास करना चाहिए read। यह बहुत ही दुर्लभ है, readइसके बजाय सही चीज़ होना बहुत दुर्लभ है read -r

{ <"/tmp/urlFile" tr -d '\r'; echo; } | while read -r url
do
  if [ -z "$url" ]; then continue; fi
  
done

3

ठीक है, readएक गलत मान देता है अगर यह एक नई सीमा से पहले फ़ाइल के अंत में मिलता है, लेकिन अगर यह भी करता है, तो यह अभी भी पढ़ा गया मान प्रदान करता है। इसलिए, हम जांच सकते हैं कि अंतिम कॉल readएक खाली लाइन की तुलना में कुछ और रिटर्न करती है, और इसे सामान्य रूप से संसाधित करती है। इसलिए, केवल readगलत रिटर्न के बाद लूप से बाहर निकलें और लाइन खाली है:

#!/bin/sh
while IFS= read -r line || [ "$line" ]; do 
    echo "line: $line"
done

$ printf 'foo\nbar' | sh ./read.sh 
line: foo
line: bar
$ printf 'foo\nbar\n' | sh ./read.sh 
line: foo
line: bar

1

एक और तरीका इस तरह होगा:

जब रीड एंड-ऑफ़-लाइन के बजाय एंड-ऑफ़-फ़ाइल तक पहुंचता है, तो यह डेटा में पढ़ता है और इसे चर को असाइन करता है, लेकिन यह एक गैर-शून्य स्थिति के साथ बाहर निकलता है। यदि आपके लूप का निर्माण किया जाता है, तो "पढ़ा; सामान करो;"

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

DONE=false
until $DONE ;do
read || DONE=true
echo $REPLY 
done < /tmp/urlFile

यहां से रेफर किया गया


1
बिल्ली "/ tmp / urlFile" | जबकि url पढ़ा
करना
    गूंज $ url
किया हुआ

यह एक बेकार उपयोग हैcat

विडंबना यह है कि आप इस catप्रक्रिया को वास्तव में उपयोगी कुछ के साथ बदल सकते हैं : एक उपकरण जो कि POSIX सिस्टम में लापता नई पंक्ति को जोड़ने और फ़ाइल को एक उचित POSIX पाठ फ़ाइल में बनाने के लिए है।

sed -e '$ a \' "/ tmp / urlFile" | जबकि पढ़ें -r url
करना
    प्रिंटफ "% s \ n" "$ {url}"
किया हुआ

आगे की पढाई


1
POSIX द्वारा सीड के व्यवहार को अनिर्दिष्ट किया जाता है जब इनपुट एक नई रेखा वर्ण में समाप्त नहीं होता है; यह भी कि जब LINE_MAX की तुलना में बड़ी लाइनें हैं, जबकि readउन मामलों में इसका व्यवहार निर्दिष्ट है।
स्टीफन चेजेलस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.