किसी वैरिएबल को मान निर्दिष्ट करके लाइन द्वारा एक फ़ाइल लाइन पढ़ें


752

मेरे पास .txt फ़ाइल है:

Marco
Paolo
Antonio

मैं इसे लाइन-दर-पंक्ति पढ़ना चाहता हूं, और प्रत्येक पंक्ति के लिए मैं एक चर के लिए एक .txt लाइन मान निर्दिष्ट करना चाहता हूं। मेरे चर का मान लेना $name, प्रवाह है:

  • फ़ाइल से पहली पंक्ति पढ़ें
  • असाइन करें $name= "मार्को"
  • के साथ कुछ कार्य करें $name
  • फ़ाइल से दूसरी पंक्ति पढ़ें
  • असाइन करें $name= "पाओलो"


3
क्या उन सवालों का किसी तरह विलय हो सकता है? दोनों के पास वास्तव में कुछ अच्छे उत्तर हैं जो समस्या के विभिन्न पहलुओं को उजागर करते हैं, बुरे उत्तरों की टिप्पणियों में गहराई से व्याख्या होती है कि उनके बारे में क्या बुरा है, और अब तक आप वास्तव में क्या विचार करने के लिए, क्या जवाब दे सकते हैं पर एक संपूर्ण अवलोकन प्राप्त नहीं कर सकते हैं। जोड़ी से एक एकल प्रश्न। 2 पृष्ठों से अधिक के बजाय एक स्थान पर यह सब करना उपयोगी होगा।
ईगोर हंस

जवाबों:


1356

निम्नलिखित एक फाइल को लाइन द्वारा तर्क लाइन के रूप में पढ़ता है:

while IFS= read -r line; do
    echo "Text read from file: $line"
done < my_filename.txt

यह एक लूप में एक फ़ाइल से लाइनों को पढ़ने के लिए मानक रूप है । स्पष्टीकरण:

  • IFS=(या IFS='') व्हाट्सएप को लीड / ट्रेल करने से रोकता है।
  • -r बैकस्लैश की व्याख्या करने से बचता है।

या आप इसे bash फ़ाइल सहायक स्क्रिप्ट, उदाहरण सामग्री में रख सकते हैं:

#!/bin/bash
while IFS= read -r line; do
    echo "Text read from file: $line"
done < "$1"

यदि उपर्युक्त फ़ाइल नाम के साथ स्क्रिप्ट में सहेजा जाता है readfile, तो इसे निम्नानुसार चलाया जा सकता है:

chmod +x readfile
./readfile filename.txt

यदि फ़ाइल मानक POSIX पाठ फ़ाइल नहीं है (= एक newline वर्ण द्वारा समाप्त नहीं किया गया है), तो लूप को आंशिक लाइनों को पीछे हटाने के लिए संशोधित किया जा सकता है:

while IFS= read -r line || [[ -n "$line" ]]; do
    echo "Text read from file: $line"
done < "$1"

यहां, || [[ -n $line ]]अंतिम पंक्ति को नजरअंदाज करने से रोकता है अगर यह एक के साथ समाप्त नहीं होता है \n(क्योंकि readयह एनओएफएफ के मुकाबले एक गैर-शून्य निकास कोड देता है)।

यदि लूप के अंदर के कमांड भी मानक इनपुट से पढ़ते हैं, तो जिस फाइल डिस्क्रिप्टर का उपयोग किया जाता है, readउसे किसी और चीज ( मानक फाइल डिस्क्रिप्टर से बचने ) के लिए जप किया जा सकता है , जैसे:

while IFS= read -r -u3 line; do
    echo "Text read from file: $line"
done 3< "$1"

(गैर-बैश गोले को नहीं जान सकते read -u3; read <&3इसके बजाय उपयोग करें ।)


23
इस विधि के साथ एक चेतावनी है। यदि लूप के अंदर कुछ भी संवादात्मक है (जैसे स्टड से पढ़ता है), तो यह $ 1 से इसका इनपुट लेगा। आपको मैन्युअल रूप से डेटा दर्ज करने का मौका नहीं दिया जाएगा।
कार्पे

10
ध्यान दें - कुछ कमांड्स (जैसे, वे लूप को तोड़ते हैं) यह। उदाहरण के लिए, ध्वज के sshबिना -nप्रभावी रूप से लूप से बच जाएगा। शायद इसके लिए एक अच्छा कारण है, लेकिन मुझे यह पता लगाने में थोड़ा समय लगा कि मेरे कोड को विफल होने से पहले मुझे पता चल गया था।
एलेक्स

6
वन-लाइनर के रूप में: जबकि IFS = '' रीड -r लाइन || [[-n "$ लाइन"]]; गूंज "$ लाइन"; किया <फ़ाइल का नाम
जोसेफ जॉनसन

8
@ Ondra stižka, यह स्टड का ffmpegसेवन करने के कारण होता है । </dev/nullअपनी ffmpegलाइन में जोड़ें और यह लूप के लिए वैकल्पिक FD का उपयोग करने में सक्षम नहीं होगा। यह "वैकल्पिक एफडी" दृष्टिकोण जैसा दिखता है while IFS='' read -r line <&3 || [[ -n "$line" ]]; do ...; done 3<"$1"
चार्ल्स डफी

9
फिर से गड़गड़ाहट : एक .shविस्तार की सलाह । यूनिक्स पर एक्ज़िबेबल्स में आमतौर पर एक्सटेंशन नहीं होते हैं (आप नहीं चलते हैं ls.elf), और एक बैश शेबंग (और बैश-केवल टूलिंग जैसे [[ ]]) और पॉसिक्स श संगतता का विस्तार करने वाला एक एक्सटेंशन आंतरिक रूप से विरोधाभासी है।
चार्ल्स डफी

309

मैं आपको उस -rध्वज का उपयोग करने के लिए प्रोत्साहित करता हूं readजिसके लिए खड़ा है:

-r  Do not treat a backslash character in any special way. Consider each
    backslash to be part of the input line.

से उद्धृत कर रहा हूँ man 1 read

एक और बात एक फ़ाइलनाम को एक तर्क के रूप में लेना है।

यहाँ अद्यतन कोड है:

#!/usr/bin/bash
filename="$1"
while read -r line; do
    name="$line"
    echo "Name read from file - $name"
done < "$filename"


@ थोमस और बीच में रिक्त स्थान का क्या होता है? संकेत: अवांछित प्रयास कमांड निष्पादन।
21

1
यह मेरे लिए काम किया, स्वीकृत उत्तर के विपरीत।
न्यूरोट्रांसमीटर

3
@TranslucentCloud, अगर यह काम किया और स्वीकृत जवाब नहीं दिया, मुझे संदेह है कि आपका शेल shनहीं था bash; || [[ -n "$line" ]]स्वीकार किए गए उत्तर में वाक्य रचना में प्रयुक्त विस्तारित परीक्षण कमांड एक बशीवाद है। उस ने कहा, उस वाक्य रचना का वास्तव में अर्थ है: यह लूप इनपुट फ़ाइल में अंतिम पंक्ति के लिए जारी रखने का कारण बनता है, भले ही इसमें कोई नई रेखा न हो। यदि आप ऐसा POSIX- संगत तरीके से करना चाहते हैं || [ -n "$line" ], तो आप इसके [बजाय का उपयोग करना चाहते हैं [[
चार्ल्स डफी

3
जिसके अनुसार, इस करता है अभी भी सेट करने के लिए संशोधित करने की आवश्यकता IFS=के लिए readखाली स्थान के ट्रिमिंग को रोकने के लिए।
चार्ल्स डफी

132

निम्नलिखित बैश टेम्पलेट का उपयोग करने से आपको फ़ाइल से एक बार में एक मान पढ़ने और उसे संसाधित करने की अनुमति मिलनी चाहिए।

while read name; do
    # Do what you want to $name
done < filename

14
एक-लाइनर के रूप में: नाम पढ़ते समय; गूंज $ {नाम}; किया <फ़ाइल का नाम
जोसेफ जॉनसन

4
@CalculusKnight, यह केवल "काम" किया क्योंकि आपने परीक्षण करने के लिए पर्याप्त दिलचस्प डेटा का उपयोग नहीं किया था। बैकस्लैश के साथ सामग्री का प्रयास करें, या एक पंक्ति जिसमें केवल शामिल है *
चार्ल्स डफी

7
@ माथियास, यह धारणा कि अंततः झूठे साबित होते हैं, बग के सबसे बड़े स्रोतों में से एक हैं, दोनों सुरक्षा-प्रभावकारी और अन्यथा। सबसे बड़ा डेटा लॉस ईवेंट मैंने कभी देखा था कि कोई ऐसा परिदृश्य जिसके कारण कोई व्यक्ति "सचमुच कभी नहीं आएगा" - फाइलों को नाम देने के लिए उपयोग किए जाने वाले बफर में रैंडम मेमोरी को डंप करने वाला एक बफर ओवरफ्लो, एक स्क्रिप्ट का कारण बनता है जिससे ऐसी धारणाएं बनती हैं जिनके बारे में संभवत: कभी भी नाम हो सकता है। बहुत, बहुत दुर्भाग्यपूर्ण व्यवहार होता है।
चार्ल्स डफी

5
@Matthias, ... और यह विशेष रूप से यहाँ सच है, क्योंकि StackOverflow में दिखाए गए कोड के नमूने का उपयोग शिक्षण साधनों के रूप में किया जाना है, ताकि लोग अपने स्वयं के काम में पैटर्न का पुन: उपयोग कर सकें!
चार्ल्स डफी

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

76
#! /bin/bash
cat filename | while read LINE; do
    echo $LINE
done

8
अन्य उत्तरों के खिलाफ कुछ भी नहीं, शायद वे अधिक परिष्कृत हैं, लेकिन मैं इस उत्तर को बढ़ाता हूं क्योंकि यह सरल, पठनीय है और जो मुझे चाहिए उसके लिए पर्याप्त है। ध्यान दें कि, इसे काम करने के लिए, पढ़ने के लिए पाठ फ़ाइल को एक रिक्त रेखा के साथ समाप्त होना चाहिए (अर्थात Enterअंतिम पंक्ति के बाद प्रेस करने की आवश्यकता है ), अन्यथा अंतिम पंक्ति को अनदेखा किया जाएगा। कम से कम मेरे साथ तो यही हुआ।
एंटोनियो विनीसियस मेनेजेस मेडे

12
बिल्ली का बेकार उपयोग, shurely?
ब्रायन एग्न्यू

5
और उद्धरण टूट गया है; और आपको अपरकेस नाम का उपयोग नहीं करना चाहिए क्योंकि वे सिस्टम उपयोग के लिए आरक्षित हैं।
ट्रिपल

7
@AntonioViniciusMenezesMedei, ... इसके अलावा, मैंने लोगों को वित्तीय घाटे को बनाए रखने के लिए देखा है क्योंकि उन्हें लगता है कि ये चेतावनी उनके लिए कभी मायने नहीं रखती; अच्छी प्रथाओं को सीखने में विफल; और फिर उन आदतों का पालन किया जो स्क्रिप्ट लिखने के लिए उपयोग की गई थीं जो महत्वपूर्ण बिलिंग डेटा का बैकअप प्रबंधित करती हैं। चीजों को सही तरीके से सीखना महत्वपूर्ण है।
चार्ल्स डफी

6
यहां एक और समस्या यह है कि पाइप एक नया सबस्क्रिप्शन खोलता है, यानी लूप के अंदर सेट किए गए सभी वेरिएबल्स को लूप खत्म होने के बाद पढ़ा नहीं जा सकता है।
mxmlnkn

20

कई लोगों ने एक समाधान पोस्ट किया है जो अधिक-अनुकूलित है। मुझे नहीं लगता कि यह गलत है, लेकिन मैं विनम्रतापूर्वक सोचता हूं कि एक कम अनुकूलित समाधान सभी को आसानी से यह समझने की अनुमति देने के लिए वांछनीय होगा कि यह कैसे काम कर रहा है। यहाँ मेरा प्रस्ताव है:

#!/bin/bash
#
# This program reads lines from a file.
#

end_of_file=0
while [[ $end_of_file == 0 ]]; do
  read -r line
  # the last exit status is the 
  # flag of the end of file
  end_of_file=$?
  echo $line
done < "$1"

20

उपयोग:

filename=$1
IFS=$'\n'
for next in `cat $filename`; do
    echo "$next read from $filename" 
done
exit 0

यदि आपने IFSअलग तरीके से सेट किया है तो आपको विषम परिणाम मिलेंगे।


34
यह एक भयानक विधि है । कृपया इसका उपयोग तब तक न करें जब तक कि आपको ग्लोबिंग की समस्या न हो, इससे पहले कि आपको इसका एहसास हो जाए!
गनीउर्फ़_निगियॉर्फ

13
@MUYBelgium क्या आपने एक ऐसी फ़ाइल के साथ कोशिश की जिसमें *एक पंक्ति में एक भी शामिल है? वैसे भी, यह एक एंटीपैटर्न हैके लिए लाइनों को न पढ़ें
गनीउरफ_गनीउरफ

2
@ OndraŽižka, readदृष्टिकोण है सर्वोत्तम प्रथाओं समुदाय सर्वसम्मति से दृष्टिकोण । आपकी टिप्पणी में आपके द्वारा उल्लिखित कैविएट वह है जो तब लागू होता है जब आपका लूप कमांड चलाता है (जैसे कि ffmpeg) जो स्टड से पढ़ता है, लूप के लिए नॉन-स्टडिन एफडी का उपयोग करके या ऐसे कमांड के इनपुट को रीडायरेक्ट करते हुए तुच्छ रूप से हल किया जाता है। इसके विपरीत, आपके for-लूप दृष्टिकोण में ग्लोबिंग बग के आसपास काम करने का मतलब शेल-ग्लोबल सेटिंग्स में बदलाव करना (और फिर उल्टा करना) है।
चार्ल्स डफी

1
@ OndraŽižka, ... इसके अलावा, forपाश दृष्टिकोण तुम यहाँ साधनों का उपयोग है कि सभी सामग्री में से पहले पाश सब पर क्रियान्वित करने शुरू कर सकते हैं पढ़ने के लिए है, आप कहीं भी अगर आप डेटा के गीगाबाइट से अधिक पाशन कर रहे हैं यह पूरी तरह से बेकार बना रही है विकलांग ग्लोबिंग; while readपाश एक समय में एक ही पंक्ति के डेटा से अधिक नहीं संग्रहीत करना होता है, जिसका अर्थ यह निष्पादित करते समय उपप्रक्रिया पैदा सामग्री अभी भी चल रहा है (इस प्रकार प्रयोजनों स्ट्रीमिंग के लिए प्रयोग करने योग्य है) शुरू कर सकते हैं, और यह भी घिरे स्मृति की खपत है।
चार्ल्स डफी

1
वास्तव में, यहां तक ​​कि- whileआधारित दृष्टिकोणों में * -चैचर मुद्दे हैं। ऊपर दिए गए स्वीकृत उत्तर की टिप्पणियाँ देखें। हालाँकि, यह एक एंटीपैटर्न होने वाली फाइलों के लिए पुनरावृति के खिलाफ बहस नहीं है।
ईगोर हंस

9

यदि आपको इनपुट फ़ाइल और उपयोगकर्ता इनपुट (या स्टड से कुछ भी) दोनों को संसाधित करने की आवश्यकता है, तो निम्न समाधान का उपयोग करें:

#!/bin/bash
exec 3<"$1"
while IFS='' read -r -u 3 line || [[ -n "$line" ]]; do
    read -p "> $line (Press Enter to continue)"
done

स्वीकार किए गए उत्तर के आधार पर और बैश-हैकर्स पर पुनर्निर्देशन ट्यूटोरियल

यहां, हम फ़ाइल डिस्क्रिप्टर 3 को स्क्रिप्ट तर्क के रूप में पास की गई फ़ाइल के लिए खोलते हैं और readइस डिस्क्रिप्टर को इनपुट ( -u 3) के रूप में उपयोग करने के लिए कहते हैं । इस प्रकार, हम टर्मिनल या किसी अन्य इनपुट स्रोत से जुड़े डिफ़ॉल्ट इनपुट डिस्क्रिप्टर (0) को छोड़ देते हैं, जो उपयोगकर्ता इनपुट को पढ़ने में सक्षम है।


7

उचित त्रुटि से निपटने के लिए:

#!/bin/bash

set -Ee    
trap "echo error" EXIT    
test -e ${FILENAME} || exit
while read -r line
do
    echo ${line}
done < ${FILENAME}

क्या आप कुछ स्पष्टीकरण जोड़ सकते हैं?
टायलर क्रिश्चियन

दुर्भाग्य से यह फ़ाइल में अंतिम पंक्ति को याद करता है।
अनगलक

... और, उद्धृत करने की कमी के कारण, मुंगेस की रेखाएं जिनमें वाइल्डकार्ड शामिल हैं - जैसा कि बैशपिटैल्स [14] में वर्णित है ।
चार्ल्स डफी

0

निम्नलिखित केवल फ़ाइल की सामग्री का प्रिंट आउट लेगा:

cat $Path/FileName.txt

while read line;
do
echo $line     
done

1
यह उत्तर वास्तव में मौजूदा उत्तरों पर कुछ भी नहीं जोड़ता है, टाइपो / बग के कारण काम नहीं करता है, और कई तरीकों से टूट जाता है।
कोनराड रुडोल्फ

0

Bash में IFS (आंतरिक क्षेत्र विभाजक) उपकरण का उपयोग करें, टोकन में अलग-अलग रेखाओं का उपयोग करके वर्ण को परिभाषित करता है, डिफ़ॉल्ट रूप से इसमें < tab > / < space > / < newLine > शामिल है।

चरण 1 : फ़ाइल डेटा लोड करें और सूची में डालें:

# declaring array list and index iterator
declare -a array=()
i=0

# reading file in row mode, insert each line into array
while IFS= read -r line; do
    array[i]=$line
    let "i++"
    # reading from file path
done < "<yourFullFilePath>"

चरण 2 : अब पुनरावृति और प्रिंट करें आउटपुट:

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

सरणी में प्रतिध्वनि विशिष्ट सूचकांक : सरणी में एक चर तक पहुँच:

echo "${array[0]}"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.