স্পেস সহ লুপের জন্য 'সম্পূর্ণ লাইন' কীভাবে পড়বেন


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=$'\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
এবং আইএফএসে একক উদ্ধৃতি সম্পর্কে যত্ন রাখুন কারণ আইএফএস = $ "\ n" এছাড়াও "এনএন" স্ট্রিংগুলিকে বিভক্ত করবে। আমি আরও জটিল সিনট্যাক্স বা ফাংশন ব্যবহারের চেয়ে আইএফএসকে আরও নির্ভরযোগ্য পেয়েছি।
erm3nda

23
স্পষ্টতই এটি unset IFSপরে পরামর্শ দেওয়া হয় , যাতে অন্য কমান্ডগুলি একই শেলটিতে প্রভাবিত না হয়।
বরিস ডাপ্পেন

2
এর $অর্থ কী IFS=$'\n'?
রেন

2
$লাইনের বিরতি স্ট্রিংয়ের ভিতরে কাজ করে। এটি local IFS=$'\n'কোনও ফাংশনের অভ্যন্তরেও করা উচিত ।
অ্যান্ডি রে

1
@ রেন যা $'...'" এএনএসআই-সি উদ্ধৃতি " হিসাবে পরিচিত
нιηসু

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। এটি পরিবেশের ভেরিয়েবলগুলি পরিবর্তন করার প্রয়োজন ছাড়াই স্পেস সহ ফাইল / ফোল্ডারের নামগুলিতে কাজ করে। খুব ভাল উত্তর।
জিশি

সেই
সময়টি

@ জিশি যেহেতু এটি প্রাথমিকভাবে প্রদর্শনের জন্য ডিজাইন করা হয়েছে এবং এটি টার্মিনাল-উইন্ডো আকারের জন্য প্রতিক্রিয়াশীল, 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
একটি এখানে স্ট্রিং! অন্যান্য সমস্ত সমাধানগুলির মধ্যে সবচেয়ে মার্জিত আইএমও
এলিরান মালকা

5

মিচেল কারির উত্তরের সামান্য বর্ধন এখানে দেওয়া হয়েছে, যেগুলি পার্শ্ব প্রতিক্রিয়াগুলির ছোট স্কোপগুলির কারণে আমি পছন্দ করি যা ভেরিয়েবল সেট করা থেকে বিরত থাকে:

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

1
আপনি অপসারণ করতে পারেন -name '*'এবং এটি একই হবে, না?
wjandrea

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 '*') ভেরিয়েবলের ফলাফল নির্ধারণের চেষ্টা করা উচিত নয় ! বা, কমপক্ষে অ্যারে ভেরিয়েবলের মাধ্যমে এ জাতীয় জিনিস করার চেষ্টা করা উচিত; আপনি যদি এত অলস হওয়ার জন্য জেদ করেন! সুতরাং, এখানে ডান্ডালফের সমাধান বিপজ্জনক চালবাজি ছাড়াই করা হয়েছে; এবং সব মিলিয়ে এক লাইনে

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

আরে @ ওডোনকোয়া, আমি ডাবল উদ্ধৃতি ব্যতীত ফাইন্ড কমান্ডটি করার চেষ্টা করেছি, তবে এটির ফলাফলগুলি সমস্তই একটি লাইন হিসাবে উপস্থিত হয়। এই কমান্ড এবং জড়িত বিপদগুলি নিয়ে আমি "অজানা পরিমাণ ইনপুট" সম্পর্কে বিভ্রান্ত। আপনি কীভাবে বিপদগুলির একটি উদাহরণ প্রদান করতে পারেন এবং কীভাবে তারা তাত্ত্বিকভাবে ঘটতে পারে? আমি গুরুত্ব সহকারে এটি সম্পর্কে অলস হতে ইচ্ছুক না, আমি অন্যান্য প্রোগ্রামিং ভাষায় আরও বেশি স্বাচ্ছন্দ্য বোধ করি।
ডান্ডালফ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.