ব্যাশে ভেরিয়েবল থেকে লাইনে কীভাবে পড়তে পারি?


48

আমার একটি ভেরিয়েবল আছে যা কমান্ডের মাল্টলাইন আউটপুট ধারণ করে। ভেরিয়েবল থেকে লাইন আউটপুট লাইন পড়ার সবচেয়ে কার্যকর উপায় কী?

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

jobs="$(jobs)"
if [ "$jobs" ]; then
    # read lines from $jobs
fi

উত্তর:


64

প্রক্রিয়া প্রতিস্থাপনের সাথে আপনি কিছুক্ষণ লুপ ব্যবহার করতে পারেন:

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এটি বিভ্রান্তি সৃষ্টি করতে পারে কারণ এটি একটি সাধারণ শেল কমান্ডেরও নাম।


3
আপনি যদি আপনার সমস্ত সাদা স্থান রাখতে চান তবে ব্যবহার করুন while IFS= read.... আপনি যদি \ ব্যাখ্যাটি রোধ করতে চান তবে ব্যবহার করুনread -r
পিটার.ও

আমি পয়েন্ট fred.bear উল্লেখ করা হয়েছে, সেইসাথে পরিবর্তিত ঠিক করেছি echoকরতে printf %s, যাতে আপনার স্ক্রিপ্টটি অ গৃহপালিত ইনপুট দিয়ে এমনকি কাজ করবে।
গিলস

মাল্টলাইন ভেরিয়েবল থেকে পড়ার জন্য, প্রিন্টফের কাছ থেকে পাইপিংয়ের জন্য এখানে একটি স্ট্রিংস পছন্দনীয় (l0b0 এর উত্তর দেখুন)।
আতা

1
@ata যদিও আমি এই "পছন্দনীয়" প্রায়শই শুনেছি, তবে এটি অবশ্যই লক্ষণীয় যে কোনও এস্ট্রাস্ট্রিংয়ের জন্য সর্বদা /tmpডিরেক্টরিটি লেখার জন্য প্রয়োজন , কারণ এটি একটি অস্থায়ী কাজের ফাইল তৈরি করতে সক্ষম হওয়ার উপর নির্ভর করে। আপনি /tmpকেবলমাত্র কেবল পঠনযোগ্য (এবং আপনার দ্বারা পরিবর্তনযোগ্য নয়) দ্বারা কোনও সীমাবদ্ধ সিস্টেমে নিজেকে খুঁজে পাওয়া উচিত , আপনি বিকল্প বিকল্প যেমন, printfপাইপের সাহায্যে ব্যবহার করার সম্ভাবনা সম্পর্কে খুশি হবেন ।
সিনট্যাক্সরোর

1
দ্বিতীয় উদাহরণে, যদি মাল্টি-লাইন ভেরিয়েবলটিতে একটি অনুবর্তনযোগ্য নিউলাইন না থাকে তবে আপনি শেষ উপাদানটি আলগা করবেন। এটিকে পরিবর্তন করুন:printf "%s\n" "$var" | while IFS= read -r line
ডেভিড এইচ। বেনেট

26

কমান্ড লাইনের আউটপুটটি রেখার মাধ্যমে ব্যাখ্যা করতে ( ব্যাখ্যা ):

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)বা পরিবর্তনশীল সাবস্টুটিনোটিনের ফলে ঘটে $fooforলুপের সব টুকরা উপর কাজ করে $(jobs), যা সব কমান্ড আউটপুটে খালি নয় এমন লাইন আছে। অবশেষে, গ্লোব্বিং এবং IFSসেটিংস পুনরুদ্ধার করুন ।


আইএফএস স্থাপন এবং আইএফএস আনসেট করা নিয়ে আমার সমস্যা হয়েছে। আমি মনে করি সঠিক কাজটি হ'ল আইএফএসের পুরানো মান সংরক্ষণ করা এবং আইএফএসকে সেই পুরানো মানকে আবার সেট করা। আমি বাশ বিশেষজ্ঞ নই, তবে আমার অভিজ্ঞতায় এটি আপনাকে আসল বাহাভায়ারে ফিরিয়ে আনবে।
বজর্ন রোচে

1
@ জর্জনরোচে: একটি ফাংশনের ভিতরে, ব্যবহার করুন local IFS=something। এটি গ্লোবাল-স্কোপ মানকে প্রভাবিত করবে না। আইআইআরসি, unset IFSআপনাকে ডিফল্টে ফিরিয়ে আনবে না (এবং এটি পূর্বনির্ধারিত আগে না হলে অবশ্যই কাজ করবে না)।
পিটার কর্ডেস

14

সমস্যা: আপনি যদি লুপটি ব্যবহার করেন তবে এটি সাবশেলে চলবে এবং সমস্ত ভেরিয়েবল নষ্ট হবে। সমাধান: লুপের জন্য ব্যবহার করুন

# 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=

তোমাকে অনেক ধন্যবাদ!! উপরের সমস্ত সমাধান আমার জন্য ব্যর্থ হয়েছে।
hax0r_n_code

ব্যাশে একটি while readলুপে পাইপিংয়ের অর্থ হল যখন লুপটি সাব-শেলের মধ্যে থাকে তাই ভেরিয়েবলগুলি বিশ্বব্যাপী নয়। while read;do ;done <<< "$var"লুপের বডিটিকে সাবসেল করে না। (সাম্প্রতিক ব্যাশের একটি cmd | whileলুপের দেহকে সাবশেলে না রাখার বিকল্প রয়েছে , যেমন খশর সবসময়ই ছিল))
পিটার কর্ডেস


10

সাম্প্রতিক ব্যাশ সংস্করণগুলিতে, অ্যারেতে কমান্ড আউটপুট দক্ষতার সাথে পড়তে mapfileবা ব্যবহার readarrayকরতে

$ readarray test < <(ls -ltrR)
$ echo ${#test[@]}
6305

দাবি অস্বীকার: ভয়ঙ্কর উদাহরণ, তবে আপনি নিজের চেয়ে ls ব্যবহার করার জন্য আরও ভাল কমান্ড নিয়ে আসতে পারেন


এটি একটি দুর্দান্ত উপায়, তবে আমার সিস্টেমে অস্থায়ী ফাইলগুলির সাথে লিটার / ভার / টিএমপি। যাইহোক +1
ইউজিন ইয়ারমশ

@ ইউজিন: এটি মজার। এটি কোন সিস্টেমে (ডিস্ট্রো / ওএস) চালু আছে?
শেহে

এটি ফ্রিবিএসডি ৮. কীভাবে পুনরুত্পাদন করবেন: readarrayএকটি ফাংশন রাখুন এবং ফাংশনটিকে কয়েকবার কল করুন।
ইউজিন ইয়ারমশ

ভাল লাগছে, +1
তেরেসা ই জুনিয়র


-1

আপনি নিউলাইন-বিচ্ছিন্ন ডেটা সহ ভেরিয়েবলটি পড়তে <<< ব্যবহার করতে পারেন:

while read -r line
do 
  echo "A line of input: $line"
done <<<"$lines"

1
ইউনিক্স ও লিনাক্সে স্বাগতম! এটি মূলত চার বছর আগে থেকে একটি উত্তর সদৃশ। আপনার অবদানের জন্য নতুন কিছু না থাকলে দয়া করে কোনও উত্তর পোস্ট করবেন না।
জি-ম্যান বলছেন 'মনিকা পুনরায় ইনস্টল করুন'
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.