কীভাবে zsh এ লাইনের একটি অ্যারে সঠিকভাবে সংগ্রহ করবেন


42

আমি ভেবেছিলাম নিম্নলিখিতগুলি আউটপুটটিকে my_commandলাইনের একটি অ্যারে গ্রুপ করবে :

IFS='\n' array_of_lines=$(my_command);

যাতে $array_of_lines[1]আউটপুট প্রথম লাইন my_command, $array_of_lines[2]দ্বিতীয়, এবং আরও উল্লেখ করবে।

তবে উপরের কমান্ডটি ভালভাবে কাজ করছে বলে মনে হচ্ছে না। my_commandচরিত্রের চারপাশের আউটপুটটিও বিভক্ত বলে মনে হয় n, যেমন আমি যাচাই print -l $array_of_linesকরেছিলাম, যা আমি বিশ্বাস করি যে অ্যারে লাইনের উপাদানগুলি রেখার সাথে প্রিন্ট করে। আমি এটি দিয়ে পরীক্ষা করে দেখেছি:

echo $array_of_lines[1]
echo $array_of_lines[2]
...

দ্বিতীয় প্রয়াসে, আমি ভেবেছিলাম যোগ করা evalসাহায্য করতে পারে:

IFS='\n' array_of_lines=$(eval my_command);

তবে আমি যেমনটি না পেয়ে ঠিক তেমন ফলাফল পেয়েছি।

পরিশেষে, zsh এর ফাঁকা জায়গাগুলি সহ উপাদানগুলির তালিকাগুলির উত্তর অনুসরণ করে আমি IFSzsh কীভাবে ইনপুটকে বিভক্ত করতে এবং উপাদানগুলিকে একটি অ্যারেতে সংগ্রহ করতে হবে তা বলার পরিবর্তে প্যারামিটার সম্প্রসারণ পতাকা ব্যবহার করার চেষ্টা করেছি , যেমন:

array_of_lines=("${(@f)$(my_command)}");

তবে আমি এখনও একই ফলাফল পেয়েছি (বিভক্ত হওয়ার ফলে n)

এটির সাথে আমার নিম্নলিখিত প্রশ্নগুলি রয়েছে:

চতুর্থাংশ 1। লাইনের অ্যারেতে কমান্ডের আউটপুট সংগ্রহ করার "সঠিক" উপায়গুলি কী কী ?

Q2 এর। আমি কীভাবে IFSকেবলমাত্র নিউলাইনগুলিতে বিভক্ত করতে নির্দিষ্ট করতে পারি ?

চতুর্থাংশ 3। আমি যদি আমার তৃতীয় প্রয়াস হিসাবে প্যারামিটার সম্প্রসারণের পতাকাগুলি ব্যবহার করি (যেমন ব্যবহার করে @f) বিভাজন নির্দিষ্ট করতে, zsh এর মানটিকে অগ্রাহ্য করে IFS? কেন এটি উপরে কাজ করে না?

উত্তর:


71

টিএল, ডিআর:

array_of_lines=("${(@f)$(my_command)}")

প্রথম ভুল (→ Q2 এর): IFS='\n'সেট IFSদুই অক্ষর \এবং nIFSএকটি নতুন লাইন সেট করতে, ব্যবহার করুন IFS=$'\n'

দ্বিতীয়ত ভুল: একটি অ্যারের মান একটি পরিবর্তনশীল সেট করতে, উপাদান প্রায় প্রথম বন্ধনী প্রয়োজন: array_of_lines=(foo bar)

এটি খালি রেখাগুলি বাদ দেওয়া ব্যতীত এটি কাজ করবে, কারণ একটানা হোয়াইটস্পেস একক বিভাজক হিসাবে গণ্য:

IFS=$'\n' array_of_lines=($(my_command))

একেবারে শেষদিকে সাদা অংশের অক্ষর দ্বিগুণ করে খালি লাইনগুলি ধরে রাখতে পারেন IFS:

IFS=$'\n\n' array_of_lines=($(my_command))

খালি রেখাগুলির পাশাপাশি চলতে রাখতে, আপনাকে কমান্ডের আউটপুটটিতে কিছু যুক্ত করতে হবে, কারণ এটি কমান্ডের পরিবর্তে নয়, কমান্ডের বিকল্পে ঘটে in

IFS=$'\n\n' array_of_lines=($(my_command; echo .)); unset 'array_of_lines[-1]'

(ধরে নিই যে আউটপুটটি my_commandএকটি সীমানা ছাড়ানো লাইনে শেষ হবে না; এছাড়াও আপনি নোটের প্রস্থান স্থিতিটি হারাবেন তা নোট করুন my_command)

মনে রাখবেন যে উপরের সমস্ত স্নিপকেটগুলি IFSতার অ-ডিফল্ট মান সহ ছেড়ে যায় , যাতে তারা পরবর্তী কোডটি বিশৃঙ্খলা করতে পারে। IFSলোকাল সেটিংস রাখতে , পুরো জিনিসটিকে এমন একটি ফাংশনে রাখুন যেখানে আপনি IFSস্থানীয় ঘোষণা করেন (এখানে কমান্ডের প্রস্থান স্থিতি সংরক্ষণের যত্ন নেওয়া):

collect_lines() {
  local IFS=$'\n\n' ret
  array_of_lines=($("$@"; ret=$?; echo .; exit $ret))
  ret=$?
  unset 'array_of_lines[-1]'
  return $ret
}
collect_lines my_command

তবে আমি গণ্ডগোল না করার পরামর্শ দিচ্ছি IFS; পরিবর্তে, fনতুন লাইনে বিভক্ত করতে প্রসারিত পতাকাটি ব্যবহার করুন (→ কিউ 1):

array_of_lines=("${(@f)$(my_command)}")

অথবা খালি লাইনগুলি অনুসরণ করার জন্য:

array_of_lines=("${(@f)$(my_command; echo .)}")
unset 'array_of_lines[-1]'

মূল্য IFSসেখানে কিছু যায় আসে না। আমি সন্দেহ করি যে আপনি একটি কমান্ড ব্যবহার করেছেন যা আপনার পরীক্ষাগুলিতে IFSমুদ্রণের জন্য বিভক্ত হয় $array_of_lines(l Q3)।


7
এতো জটিল! "${(@f)...}"হিসাবে একই ${(f)"..."}, কিন্তু অন্যভাবে। (@)ডাবল কোটের অভ্যন্তরের অর্থ "অ্যারের উপাদান অনুসারে একটি শব্দ অর্জন করুন" এবং এর (f)অর্থ "নিউলাইন দ্বারা অ্যারেতে বিভক্ত" means পিএস: দয়া করে দস্তাবেজের সাথে
উড়ন্ত ভেড়া

3
@ ফ্লাইংশিপ, কোনও ${(f)"..."}খালি লাইন এড়িয়ে যাবে না , "${(@f)...}"সেগুলি সংরক্ষণ করে। যে মধ্যে একই পার্থক্য নেই $argvএবং "$argv[@]"। যে "$@"জিনিস একটি অ্যারের সব উপাদান সংরক্ষণ দেরী 70s মধ্যে বোর্ন শেল থেকে আসে।
স্টাফেন চেজেলাস

4

দুটি বিষয়: প্রথমত, দৃশ্যত ডাবল উদ্ধৃতিগুলি ব্যাকস্ল্যাশ পলায়নেরও ব্যাখ্যা দেয় না (তার জন্য দুঃখিত :) $'...'উদ্ধৃতি ব্যবহার করুন । এবং অনুসারে man zshparam, একটি অ্যারেতে শব্দ সংগ্রহ করার জন্য আপনাকে সেগুলি বন্ধনীতে আবদ্ধ করতে হবে। সুতরাং এটি কাজ করে:

% touch 'a b' c d 'e f'
% IFS=$'\n' arr=($(ls)); print -l $arr
a b
c
d
e f
% print $arr[1]
a b

আমি আপনার Q3 উত্তর দিতে পারে না। আমি আশা করি এরকম রহস্যজনক বিষয়গুলি আমার কখনই জানতে হবে না :)।


-2

স্থান সহ নতুন লাইনটি প্রতিস্থাপন করতে আপনি ট্র ব্যবহার করতে পারেন:

lines=($(mycommand | tr '\n' ' '))
select line in ("${lines[@]}"); do
  echo "$line"
  break
done

3
লাইনে স্পেস থাকলে কী হবে?
don_crissti

2
ওটা কোন অর্থ প্রকাশ করে না. এসপিসি এবং এনএল উভয়ই এর ডিফল্ট মান $IFS। একজনের সাথে অন্যের কাছে অনুবাদ করা কোনও তাত্পর্য রাখে না।
স্টাফেন চেজেলাস

আমার সম্পাদনাগুলি কি যুক্তিসঙ্গত ছিল? আমি এটি যেমন ছিল তেমন কাজ করতে পারি না
জন পি

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