আমার একটি ভেরিয়েবল আছে যা কমান্ডের মাল্টলাইন আউটপুট ধারণ করে। ভেরিয়েবল থেকে লাইন আউটপুট লাইন পড়ার সবচেয়ে কার্যকর উপায় কী?
উদাহরণ স্বরূপ:
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