আমার একটি ভেরিয়েবল আছে যা কমান্ডের মাল্টলাইন আউটপুট ধারণ করে। ভেরিয়েবল থেকে লাইন আউটপুট লাইন পড়ার সবচেয়ে কার্যকর উপায় কী?
উদাহরণ স্বরূপ:
jobs="$(jobs)"
if [ "$jobs" ]; then
# read lines from $jobs
fi
আমার একটি ভেরিয়েবল আছে যা কমান্ডের মাল্টলাইন আউটপুট ধারণ করে। ভেরিয়েবল থেকে লাইন আউটপুট লাইন পড়ার সবচেয়ে কার্যকর উপায় কী?
উদাহরণ স্বরূপ:
jobs="$(jobs)"
if [ "$jobs" ]; then
# read lines from $jobs
fi
উত্তর:
প্রক্রিয়া প্রতিস্থাপনের সাথে আপনি কিছুক্ষণ লুপ ব্যবহার করতে পারেন:
while read -r line
do
echo "$line"
done < <(jobs)
মাল্টলাইন ভেরিয়েবলটি পড়ার একটি সর্বোত্তম উপায় হ'ল একটি ফাঁকা IFS
ভেরিয়েবল এবং printf
একটি চলন্ত নিউলাইন সহ ভেরিয়েবল সেট করা :
# Printf '%s\n' "$var" is necessary because printf '%s' "$var" on a
# variable that doesn't end with a newline then the while loop will
# completely miss the last line of the variable.
while IFS= read -r line
do
echo "$line"
done < <(printf '%s\n' "$var")
দ্রষ্টব্য: শেলচেক sc2031 অনুসারে , সাবস্কেল তৈরি করা [সূক্ষ্মভাবে] এড়াতে কোনও পাইপের কাছে প্রক্রিয়া সাবস্টিটিশন ব্যবহার করা ভাল।
এছাড়াও, দয়া করে বুঝতে পারেন যে ভেরিয়েবলের নামকরণের ফলে jobs
এটি বিভ্রান্তি সৃষ্টি করতে পারে কারণ এটি একটি সাধারণ শেল কমান্ডেরও নাম।
echo
করতে printf %s
, যাতে আপনার স্ক্রিপ্টটি অ গৃহপালিত ইনপুট দিয়ে এমনকি কাজ করবে।
/tmp
ডিরেক্টরিটি লেখার জন্য প্রয়োজন , কারণ এটি একটি অস্থায়ী কাজের ফাইল তৈরি করতে সক্ষম হওয়ার উপর নির্ভর করে। আপনি /tmp
কেবলমাত্র কেবল পঠনযোগ্য (এবং আপনার দ্বারা পরিবর্তনযোগ্য নয়) দ্বারা কোনও সীমাবদ্ধ সিস্টেমে নিজেকে খুঁজে পাওয়া উচিত , আপনি বিকল্প বিকল্প যেমন, printf
পাইপের সাহায্যে ব্যবহার করার সম্ভাবনা সম্পর্কে খুশি হবেন ।
printf "%s\n" "$var" | while IFS= read -r line
কমান্ড লাইনের আউটপুটটি রেখার মাধ্যমে ব্যাখ্যা করতে ( ব্যাখ্যা ):
jobs |
while IFS= read -r line; do
process "$line"
done
আপনার যদি ইতিমধ্যে কোনও ভেরিয়েবলের ডেটা থাকে:
printf %s "$foo" | …
printf %s "$foo"
প্রায় অনুরূপ echo "$foo"
, তবে $foo
আক্ষরিকভাবে মুদ্রণ করে , যদিও এটি ইকো কমান্ডের বিকল্প হিসাবে echo "$foo"
ব্যাখ্যা করতে পারে $foo
যদি এটি একটি দিয়ে শুরু -
হয় $foo
এবং কিছু শেলের মধ্যে ব্যাকস্ল্যাশ ক্রম প্রসারিত করতে পারে ।
নোট করুন যে কয়েকটি শেলের (ছাই, বাশ, পিডিএক্স, তবে কেএস বা জেড নয়) পাইপলাইনের ডান হাতটি পৃথক প্রক্রিয়াতে চলে, সুতরাং লুপে আপনি যে কোনও পরিবর্তনকটি সেট করেছেন তা হারিয়ে গেছে। উদাহরণস্বরূপ, এই শেলগুলিতে নিম্নলিখিত লাইন-গণনা স্ক্রিপ্ট 0 টি মুদ্রণ করে:
n=0
printf %s "$foo" |
while IFS= read -r line; do
n=$(($n + 1))
done
echo $n
একটি কার্যপ্রণালী হ'ল স্ক্রিপ্টের বাকী অংশটি (বা কমপক্ষে যে অংশটি $n
লুপ থেকে মূল্য প্রয়োজন তার জন্য ) একটি কমান্ড তালিকায় রাখবে:
n=0
printf %s "$foo" | {
while IFS= read -r line; do
n=$(($n + 1))
done
echo $n
}
খালি নয় এমন লাইনে অভিনয় করা যদি যথেষ্ট ভাল হয় এবং ইনপুটটি বিশাল না হয় তবে আপনি শব্দ বিভাজন ব্যবহার করতে পারেন:
IFS='
'
set -f
for line in $(jobs); do
# process line
done
set +f
unset IFS
ব্যাখ্যা: IFS
একক নতুন লাইনে সেট করা কেবলমাত্র নিউলাইনগুলিতে শব্দ বিভাজন ঘটায় (ডিফল্ট সেটিংসের অধীনে কোনও হোয়াইটস্পেসের অক্ষরের বিপরীতে)। set -f
গ্লোববিং (অর্থাত্ ওয়াইল্ডকার্ড সম্প্রসারণ) বন্ধ করে দেয়, যা অন্যথায় কমান্ড প্রতিস্থাপন $(jobs)
বা পরিবর্তনশীল সাবস্টুটিনোটিনের ফলে ঘটে $foo
। for
লুপের সব টুকরা উপর কাজ করে $(jobs)
, যা সব কমান্ড আউটপুটে খালি নয় এমন লাইন আছে। অবশেষে, গ্লোব্বিং এবং IFS
সেটিংস পুনরুদ্ধার করুন ।
local IFS=something
। এটি গ্লোবাল-স্কোপ মানকে প্রভাবিত করবে না। আইআইআরসি, unset IFS
আপনাকে ডিফল্টে ফিরিয়ে আনবে না (এবং এটি পূর্বনির্ধারিত আগে না হলে অবশ্যই কাজ করবে না)।
সমস্যা: আপনি যদি লুপটি ব্যবহার করেন তবে এটি সাবশেলে চলবে এবং সমস্ত ভেরিয়েবল নষ্ট হবে। সমাধান: লুপের জন্য ব্যবহার করুন
# change delimiter (IFS) to new line.
IFS_BAK=$IFS
IFS=$'\n'
for line in $variableWithSeveralLines; do
echo "$line"
# return IFS back if you need to split new line by spaces:
IFS=$IFS_BAK
IFS_BAK=
lineConvertedToArraySplittedBySpaces=( $line )
echo "{lineConvertedToArraySplittedBySpaces[0]}"
# return IFS back to newline for "for" loop
IFS_BAK=$IFS
IFS=$'\n'
done
# return delimiter to previous value
IFS=$IFS_BAK
IFS_BAK=
while read
লুপে পাইপিংয়ের অর্থ হল যখন লুপটি সাব-শেলের মধ্যে থাকে তাই ভেরিয়েবলগুলি বিশ্বব্যাপী নয়। while read;do ;done <<< "$var"
লুপের বডিটিকে সাবসেল করে না। (সাম্প্রতিক ব্যাশের একটি cmd | while
লুপের দেহকে সাবশেলে না রাখার বিকল্প রয়েছে , যেমন খশর সবসময়ই ছিল))
সাম্প্রতিক ব্যাশ সংস্করণগুলিতে, অ্যারেতে কমান্ড আউটপুট দক্ষতার সাথে পড়তে mapfile
বা ব্যবহার readarray
করতে
$ readarray test < <(ls -ltrR)
$ echo ${#test[@]}
6305
দাবি অস্বীকার: ভয়ঙ্কর উদাহরণ, তবে আপনি নিজের চেয়ে ls ব্যবহার করার জন্য আরও ভাল কমান্ড নিয়ে আসতে পারেন
readarray
একটি ফাংশন রাখুন এবং ফাংশনটিকে কয়েকবার কল করুন।
আপনি নিউলাইন-বিচ্ছিন্ন ডেটা সহ ভেরিয়েবলটি পড়তে <<< ব্যবহার করতে পারেন:
while read -r line
do
echo "A line of input: $line"
done <<<"$lines"
while IFS= read
.... আপনি যদি \ ব্যাখ্যাটি রোধ করতে চান তবে ব্যবহার করুনread -r