ভেরিয়েবলের মান নির্ধারণ করে লাইনের দ্বারা একটি ফাইল লাইন পড়ুন


752

আমার কাছে নিম্নলিখিত। টেক্সট ফাইল রয়েছে:

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 ব্যাকস্ল্যাশ ব্যাখ্যা থেকে বাঁচতে বাধা দেয়।

বা আপনি এটি একটি বাশ ফাইল সহায়ক স্ক্রিপ্টে রাখতে পারেন, উদাহরণস্বরূপ সামগ্রী:

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

যদি উপরেরটি ফাইলের নাম সহ কোনও স্ক্রিপ্টে সংরক্ষণ করা হয় তবে readfileএটি নিম্নরূপে চালানো যেতে পারে:

chmod +x readfile
./readfile filename.txt

যদি ফাইলটি কোনও স্ট্যান্ডার্ড পসিক্স টেক্সট ফাইল না হয় (= একটি নতুন লাইনের চরিত্র দ্বারা শেষ করা হয় না), আংশিক লাইনগুলি অনুসরণ করার জন্য লুপটি পরিবর্তন করা যেতে পারে:

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 থেকে নেওয়া হবে। আপনাকে ম্যানুয়ালি ডেটা প্রবেশের সুযোগ দেওয়া হবে না।
carpie

10
লক্ষণীয় - কিছু কমান্ডগুলি এটিকে ভেঙে দেয় (যেমন তারা লুপটি ভেঙে দেয়)। উদাহরণস্বরূপ, পতাকা sshছাড়াই -nকার্যকরভাবে আপনাকে লুপ থেকে বাঁচার কারণ হবে। এটির জন্য সম্ভবত একটি ভাল কারণ আছে তবে এটি আবিষ্কার করার আগে আমার কোডটি কীভাবে ব্যর্থ হয়েছিল তা খালি করতে আমার কিছুটা সময় নিয়েছিল।
অ্যালেক্স

6
ওয়ান-লাইনার হিসাবে: যখন আইএফএস = '' পঠন-রেখা || [[-n "$ লাইন"]]; "$ লাইন" প্রতিধ্বনি করুন; সম্পন্ন <ফাইল নাম
জোসেফ জনসন

8
@ ওন্দ্রেইকা, স্টিডিন সেবন করার কারণে এটি ঘটে ffmpeg। যোগ </dev/nullআপনার টু ffmpegলাইন এবং এটি সক্ষম না হতে পারে, অথবা লুপ করার জন্য একটি বিকল্প এফডি ব্যবহার করবে। "বিকল্প এফডি" পদ্ধতির মত দেখাচ্ছে 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"

4
লাইন থেকে শীর্ষস্থানীয় এবং পিছনে স্থান
ছাঁটাই

@ থমাস এবং মাঝখানে ফাঁক দিয়ে কী হবে? ইঙ্গিত: অবাঞ্ছিত কমান্ড কার্যকর করার চেষ্টা করা হয়েছে।
কুমারশ

1
এটি গ্রহণযোগ্য উত্তরের বিপরীতে আমার পক্ষে কাজ করেছিল।
নিউরোট্রান্সমিটার

3
@ ট্রান্সলুসেন্টক্লাউড, যদি এটি কাজ করে এবং গৃহীত উত্তরটি না করে, তবে আমি সন্দেহ করি যে আপনার শেলটি ছিল shনা bash; || [[ -n "$line" ]]গৃহীত উত্তরে সিনট্যাক্সে ব্যবহৃত বর্ধিত পরীক্ষা কমান্ডটি বাশিজম। এটি বলেছিল যে সিনট্যাক্সটি আসলে প্রাসঙ্গিক অর্থ: এটি কোনও লাইন না থাকলেও ইনপুট ফাইলের শেষ লাইনটির জন্য লুপটি চালিয়ে যায়। আপনি যদি পসিক্স-আনুগত্যের উপায়ে এটি করতে চান || [ -n "$line" ], আপনি [বরং এটির চেয়ে ব্যবহার করতে চান [[
চার্লস ডাফি

3
তাই বলা হয়, এই নেই এখনও সেট রুপান্তরিত করা প্রয়োজন IFS=জন্য readহোয়াইটস্পেস ছাঁটাই প্রতিরোধ।
চার্লস ডাফি

131

নিম্নলিখিত বাশ টেমপ্লেটটি ব্যবহার করা আপনাকে ফাইল থেকে একবারে একটি মান পড়তে এবং প্রক্রিয়া করার অনুমতি দেয়।

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

14
ওয়ান-লাইনার হিসাবে: নাম পড়ার সময়; প্রতিধ্বনি $ {নাম}; সম্পন্ন <ফাইল নাম
জোসেফ জনসন

4
@ ক্যালকুলাসকাইট, এটি কেবল "কাজ করেছে" কারণ আপনি পরীক্ষার জন্য পর্যাপ্ত আকর্ষণীয় ডেটা ব্যবহার করেননি। ব্যাকস্ল্যাশ সহ সামগ্রীগুলি চেষ্টা করুন বা কেবল একটি লাইন রয়েছে *
চার্লস ডাফি

7
@ মাথিয়াস, অনুমানগুলি যা শেষ পর্যন্ত মিথ্যা বলে প্রমাণিত হয় সেগুলি নিরাপত্তা-প্রভাবিত এবং অন্যথায় উভয়ই বাগের বৃহত্তম উত্স। সবচেয়ে বড় ডেটা লোকসানের ঘটনাটি আমি দেখেছি এমন একটি দৃশ্যের কারণে হয়েছিল যে কেউ ধরে নিয়েছিল "আক্ষরিক অর্থে কখনই আসবে না" - একটি বাফার ওভারফ্লো ফাইলের নামকরণে একটি বাফারে র্যান্ডম মেমরি ডাম্প করে, যার ফলে এমন স্ক্রিপ্ট তৈরি হয়েছিল যা অনুমান করেছিল যে নামগুলি সম্ভবত কখনও থাকতে পারে খুব দুর্ভাগ্যজনক আচরণ হয় have
চার্লস ডাফি

5
@ মাথিয়াস, ... এবং এটি এখানে বিশেষত সত্য, যেহেতু স্ট্যাকওভারফ্লোতে প্রদর্শিত কোড নমুনাগুলি তাদের নিজস্ব কাজগুলিতে নিদর্শনগুলি পুনরায় ব্যবহার করার জন্য শিক্ষামূলক সরঞ্জাম হিসাবে ব্যবহার করার উদ্দেশ্যে করা হয়েছে!
চার্লস ডাফি

5
@ মাথিয়াস, আমি এই দাবির সাথে সম্পূর্ণই একমত নই যে "" আপনার প্রত্যাশিত ডেটার জন্য আপনার নিজের কোডটি তৈরি করা উচিত "। অপ্রত্যাশিত ক্ষেত্রে যেখানে আপনার বাগগুলি রয়েছে, যেখানে আপনার সুরক্ষা দুর্বলতা রয়েছে - সেগুলি পরিচালনা করা হ'ল স্ল্যাপড্যাশ কোড এবং শক্তিশালী কোডের মধ্যে পার্থক্য। মঞ্জুরি, হ্যান্ডলিংটি অভিনব হওয়ার দরকার নেই - এটি কেবল "একটি ত্রুটির সাথে প্রস্থান" হতে পারে - তবে যদি আপনার কোনও পরিচালনা নেই তবে অপ্রত্যাশিত ক্ষেত্রে আপনার আচরণ অপরিজ্ঞাত ef
চার্লস ডাফি

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

8
অন্যান্য উত্তরের বিপরীতে কিছুই নয়, সম্ভবত এগুলি আরও নমনীয়, তবে আমি এই উত্তরটিকে সমর্থন করেছি কারণ এটি সহজ, পঠনযোগ্য এবং আমার যা প্রয়োজন তা যথেষ্ট। দ্রষ্টব্য, এটি কাজ করার জন্য, পাঠ্য ফাইলটি পড়ার অবশ্যই একটি ফাঁকা রেখার সাথে শেষ করা উচিত (অর্থাত্ Enterশেষ পংক্তির পরে একটি চাপতে হবে ), অন্যথায় শেষ লাইনটি উপেক্ষা করা হবে। কমপক্ষে আমার ক্ষেত্রেও তাই ঘটেছে।
অ্যান্টোনিও ভিনিসিয়াস মেনেজেস মেদেই

12
বিড়ালের অকেজো ব্যবহার, শিউরেলি?
ব্রায়ান অ্যাগনিউ

5
এবং উদ্ধৃতি ভেঙে গেছে; এবং আপনার বড় আকারের পরিবর্তনশীল নাম ব্যবহার করা উচিত নয় কারণ সেগুলি সিস্টেমের ব্যবহারের জন্য সংরক্ষিত।
ট্রিপলি

7
@ অ্যান্টনোভিনিউসিয়াস মেনেজেসমেদী, ... আরও, আমি দেখেছি লোকেরা আর্থিক ক্ষয়ক্ষতি বজায় রাখে কারণ তারা ধরে নিয়েছিল যে এই গুপ্তচরগুলি তাদের পক্ষে কোন লাভ হবে না; ভাল অনুশীলন শিখতে ব্যর্থ; এবং এরপরে স্ক্রিপ্টগুলি লেখার সময় তারা যে অভ্যাসগুলি ব্যবহার করেছিল সেগুলি অনুসরণ করে যা সমালোচনামূলক বিলিং ডেটার ব্যাকআপ পরিচালনা করে। জিনিসগুলি সঠিকভাবে করতে শেখা গুরুত্বপূর্ণ।
চার্লস ডাফি

6
এখানে আরেকটি সমস্যা হ'ল পাইপটি একটি নতুন সাবশেল খোলে, লুপের অভ্যন্তরে সেট করা সমস্ত ভেরিয়েবলগুলি লুপ শেষ হওয়ার পরে পড়া যায় না।
এমএক্সএমএনএনএনএন

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
এটি একটি ভয়ঙ্কর পদ্ধতি । আপনি উপলব্ধি করার আগে সংঘটিত সমস্যা নিয়ে যদি সমস্যা না ঘটে তবে দয়া করে এটি ব্যবহার করবেন না!
gniourf_gniourf

13
@ মিউইবেলজিয়াম আপনি কি এমন একটি ফাইল দিয়ে চেষ্টা করেছেন যাতে *একটি লাইনে একক থাকে ? যাইহোক, এটি একটি অ্যান্টিপ্যাটার্নজন্য লাইন পড়বেন না
gniourf_gniourf

2
@ ওন্দ্রেইকা, এই readদৃষ্টিভঙ্গিটি সম্প্রদায়ের sensকমত্যের দ্বারা সর্বোত্তম-অনুশীলন পদ্ধতি । আপনার মন্তব্যে আপনি যে সতর্কতা উল্লেখ করেছেন সেটি হ'ল প্রযোজ্য যখন আপনার লুপটি কমান্ড চালায় যখন (যেমন ffmpeg) স্টিডিন থেকে পড়া, লুপের জন্য নন-স্টিডিন এফডি ব্যবহার করে বা এই জাতীয় কমান্ডের ইনপুট পুনর্নির্দেশের মাধ্যমে তুচ্ছভাবে সমাধান করা হয়। বিপরীতে, আপনার- forলুপ পদ্ধতির গ্লোবাইং বাগের চারপাশে কাজ করার অর্থ শেল-গ্লোবাল সেটিংস পরিবর্তন করা (এবং তারপরে বিপরীত হওয়া প্রয়োজন)।
চার্লস ডাফি

1
@ ওন্দ্রাŽাকা, ... তদুপরি, forআপনি এখানে লুপ পদ্ধতির ব্যবহারের অর্থ হ'ল লুপটি কার্যকর করা শুরু করার আগে সমস্ত বিষয়বস্তুটি পড়তে হবে, আপনি যদি অক্ষম করেও রেখেছেন এমনকি যদি আপনি গিগাবাইটের ডেটা লুপ করছেন তবে এটি সম্পূর্ণরূপে অকেজো হয়ে যায় globbing; while readলুপ একটি সময়ে একটি একক লাইন ডেটা বেশী সঞ্চয় করে, যার অর্থ এটি নির্বাহ যখন subprocess উৎপাদিত সামগ্রী এখনও চলছে (সুতরাং উদ্দেশ্যে স্ট্রিমিং করার জন্য ব্যবহারযোগ্য হচ্ছে) শুরু করতে পারেন, এবং এছাড়াও বেষ্টিত মেমরির খরচ হয়েছে।
চার্লস ডাফি

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}

আপনি কিছু ব্যাখ্যা যোগ করতে পারেন?
টাইলার ক্রিশ্চান

দুর্ভাগ্যক্রমে এটি ফাইলের শেষ লাইনটি মিস করে।
ungalcrys

... এবং এছাড়াও, উদ্ধৃতি না দেওয়ার কারণে, ওয়াইল্ডকার্ডযুক্ত লাইনগুলিকে মুগ্ধ করে - বাশপিত্স # 14-এ বর্ণিত ।
চার্লস ডাফি

0

নিম্নলিখিতটি কেবল ফাইলটির সামগ্রী মুদ্রণ করবে:

cat $Path/FileName.txt

while read line;
do
echo $line     
done

1
এই উত্তরটি আসলে বিদ্যমান উত্তরের চেয়ে কিছুই যুক্ত করে না, টাইপো / বাগের কারণে কাজ করে না এবং বিভিন্নভাবে ব্রেক হয়।
কনরাড রুডল্ফ

0

ব্যাশে আইএফএস (অভ্যন্তরীণ ক্ষেত্র বিভাজক) সরঞ্জামটি ব্যবহার করুন, টোকেনগুলিতে পৃথক রেখাগুলি ব্যবহার করে অক্ষরকে সংজ্ঞায়িত করা হয়েছে, ডিফল্টরূপে < ট্যাব < /> স্থান > / <নতুন লাইন >

পদক্ষেপ 1 : ফাইল ডেটা লোড করুন এবং তালিকায় inোকান:

# 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]}"
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.