বাশ: একটি ভেরিয়েবলের লাইনগুলি ওপারে আইট্রেট করা


225

বাশে লাইনগুলিতে কোনও পরিবর্তনশীল বা কমান্ডের আউটপুট থেকে কীভাবে সঠিকভাবে পুনরাবৃত্তি হয়? কেবলমাত্র একটি নতুন লাইনে আইএফএস ভেরিয়েবল সেট করা একটি কমান্ডের আউটপুটে কাজ করে তবে নতুন লাইন যুক্ত ভেরিয়েবল প্রক্রিয়া করার সময় নয়।

উদাহরণ স্বরূপ

#!/bin/bash

list="One\ntwo\nthree\nfour"

#Print the list with echo
echo -e "echo: \n$list"

#Set the field separator to new line
IFS=$'\n'

#Try to iterate over each line
echo "For loop:"
for item in $list
do
        echo "Item: $item"
done

#Output the variable to a file
echo -e $list > list.txt

#Try to iterate over each line from the cat command
echo "For loop over command output:"
for item in `cat list.txt`
do
        echo "Item: $item"
done

এটি আউটপুট দেয়:

echo: 
One
two
three
four
For loop:
Item: One\ntwo\nthree\nfour
For loop over command output:
Item: One
Item: two
Item: three
Item: four

যেমন আপনি দেখতে পাচ্ছেন, ভেরিয়েবল প্রতিধ্বনি করা বা catকমান্ডের মাধ্যমে পুনরাবৃত্তি প্রতিটি লাইনকে একে একে সঠিকভাবে মুদ্রণ করে। তবে লুপের জন্য প্রথমটি একক লাইনে সমস্ত আইটেম মুদ্রণ করে। কোন ধারনা?


সমস্ত উত্তরের জন্য কেবল একটি মন্তব্য: নতুন লাইনের চরিত্রটি ছাঁটাতে আমাকে $ (প্রতিধ্বনি "$ লাইন" | সেড-ই'স / ^ [[: স্পেস:]] * // ') করতে হয়েছিল।
সার্ভারম্যানফেল

উত্তর:


290

বাশ সহ, আপনি যদি একটি স্ট্রিংয়ে নতুনলাইনগুলি এম্বেড করতে চান তবে স্ট্রিংটি এর সাথে বন্ধ করুন $'':

$ list="One\ntwo\nthree\nfour"
$ echo "$list"
One\ntwo\nthree\nfour
$ list=$'One\ntwo\nthree\nfour'
$ echo "$list"
One
two
three
four

এবং আপনার যদি ইতিমধ্যে কোনও চলকটিতে এরকম স্ট্রিং থাকে তবে আপনি এটিকে লাইন-লাইন পড়তে পারেন:

while read -r line; do
    echo "... $line ..."
done <<< "$list"

30
শুধু একটি দয়া করে মনে রাখবেন done <<< "$list"অত্যন্ত গুরুত্বপূর্ণ
জেসন Axelson

21
কারণটি done <<< "$list"অত্যন্ত গুরুত্বপূর্ণ কারণ এটি "তালিকা" "ইনপুট হিসাবে পাস করবেread
উইসবুকি

22
আমাকে এটির $listউপর চাপ দেওয়া দরকার: ডাবল-কোয়েটিং অত্যন্ত গুরুত্বপূর্ণ।
আন্দ্রে চেল্লা

8
echo "$list" | while ...চেয়ে আরো স্পষ্ট দেখা দিতে পারে... done <<< "$line"
kyb

5
সেই পদ্ধতির ডাউনসাইড যেমন রয়েছে যেহেতু লুপটি সাব-শেলের সাথে চলবে: লুপে নির্ধারিত কোনও ভেরিয়েবল স্থায়ী হবে না।
গ্লেন জ্যাকম্যান

66

আপনি while+ ব্যবহার করতে পারেন read:

some_command | while read line ; do
   echo === $line ===
done

BTW। -eবিকল্প echoঅ মান। printfপরিবর্তে, যদি আপনি বহনযোগ্যতা চান ব্যবহার করুন ।


12
মনে রাখবেন যে আপনি যদি এই সিনট্যাক্সটি ব্যবহার করেন তবে লুপের অভ্যন্তরে নির্ধারিত ভেরিয়েবলগুলি লুপের পরে আটকে থাকবে না। আশ্চর্যের ব্যাপার যে, <<<সংস্করণ গ্লেন জ্যাকম্যান দ্বারা প্রস্তাবিত নেই পরিবর্তনশীল নিয়োগ সঙ্গে কাজ করে।
স্পারহাক

7
@ স্পারহাক হ্যাঁ, কারণ পাইপটি whileঅংশটি সম্পাদন করে একটি সাবশেল শুরু করে । <<<সংস্করণ না (নতুন ব্যাশ সংস্করণে, অন্তত)।
ম্যাক্সেলস্ট

26
#!/bin/sh

items="
one two three four
hello world
this should work just fine
"

IFS='
'
count=0
for item in $items
do
  count=$((count+1))
  echo $count $item
done

2
এটি লাইন নয়, সমস্ত আইটেম আউটপুট করে।
টমাসজ পজিউজনি

4
@ TomaszPosłuszny না, এটি আমার মেশিনে 3 (গণনা 3) লাইন আউটপুট করে। আইএফএসের সেটিংটি নোট করুন। আপনি IFS=$'\n'একই প্রভাব জন্য ব্যবহার করতে পারেন ।
jmiserez

11

লুপের জন্য আপনার করার একটি মজার উপায় এখানে:

for item in ${list//\\n/
}
do
   echo "Item: $item"
done

আরেকটু বুদ্ধিমান / পাঠযোগ্য হবে:

cr='
'
for item in ${list//\\n/$cr}
do
   echo "Item: $item"
done

তবে এটি খুব জটিল, আপনার কেবল সেখানে একটি স্থান প্রয়োজন:

for item in ${list//\\n/ }
do
   echo "Item: $item"
done

আপনার $lineভেরিয়েবলটিতে নিউলাইনগুলি থাকে না। এটি \অনুসরণ করার উদাহরণ রয়েছে n। আপনি এটি স্পষ্টরূপে দেখতে পাবেন:

$ cat t.sh
#! /bin/bash
list="One\ntwo\nthree\nfour"
echo $list | hexdump -C

$ ./t.sh
00000000  4f 6e 65 5c 6e 74 77 6f  5c 6e 74 68 72 65 65 5c  |One\ntwo\nthree\|
00000010  6e 66 6f 75 72 0a                                 |nfour.|
00000016

প্রতিস্থাপন স্থানগুলির সাথে প্রতিস্থাপন করছে, এটি লুপগুলির জন্য কাজ করার জন্য যথেষ্ট:

$ cat t.sh
#! /bin/bash
list="One\ntwo\nthree\nfour"
echo ${list//\\n/ } | hexdump -C

$ ./t.sh 
00000000  4f 6e 65 20 74 77 6f 20  74 68 72 65 65 20 66 6f  |One two three fo|
00000010  75 72 0a                                          |ur.|
00000013

ডেমো:

$ cat t.sh
#! /bin/bash
list="One\ntwo\nthree\nfour"
echo ${list//\\n/ } | hexdump -C
for item in ${list//\\n/ } ; do
    echo $item
done

$ ./t.sh 
00000000  4f 6e 65 20 74 77 6f 20  74 68 72 65 65 20 66 6f  |One two three fo|
00000010  75 72 0a                                          |ur.|
00000013
One
two
three
four

আকর্ষণীয়, আপনি এখানে কি চলছে তা ব্যাখ্যা করতে পারেন? দেখে মনে হচ্ছে আপনি একটি নতুন লাইনের সাথে \ n প্রতিস্থাপন করছেন ... মূল স্ট্রিং এবং নতুনটির মধ্যে পার্থক্য কী?
অ্যালেক্স স্পার্লিং

@ অ্যালেক্স: আমার উত্তর আপডেট করেছে - খুব সহজ সংস্করণ সহ :-)
মাদুর

আমি এটি চেষ্টা করেছিলাম এবং যদি আপনার ইনপুটটিতে ফাঁকা স্থান থাকে তবে তা কাজ করে না। উপরের উদাহরণে আমাদের কাছে "এক t ntw \ n ত্রি" আছে এবং এটি কাজ করে তবে এটি ব্যর্থ হয় যদি আমাদের কাছে "এন্ট্রি ওয়ান \ ন্যান্ট্রি টু \ এনট্রি থ্রি" থাকে কারণ এটি স্থানের জন্যও একটি নতুন লাইন যুক্ত করে।
জন রোচা

2
কেবলমাত্র একটি নোট যা সংজ্ঞায়নের পরিবর্তে crআপনি ব্যবহার করতে পারেন $'\n'
ডিভিস 1

1

আপনি প্রথমে ভেরিয়েবলটিকে একটি অ্যারেতে রূপান্তর করতে পারেন, তারপরে এটি পুনরাবৃত্তি করতে পারেন।

lines="abc
def
ghi"

declare -a theArray

while read -r line
do
    theArray+=($line)            
done <<< "$lines"

for line in "${theArray[@]}"
do
    echo "$line"
    #Do something complex here that would break your read loop
done

এটি কেবলমাত্র তখনই কার্যকর যখন আপনি চান না করতে চান IFSএবং readকমান্ডের সাথে সমস্যাও তৈরি করতে চান না , যেমনটি ঘটতে পারে আপনি যদি লুপটির অভ্যন্তরে অন্য কোনও স্ক্রিপ্ট কল করেন যে স্ক্রিপ্টটি ফিরে আসার আগে আপনার পঠন বাফারটি খালি করতে পারে, যেমনটি আমার ক্ষেত্রে হয়েছিল happened ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.