BASH সহযোগী অ্যারে মুদ্রণ


17

সমস্ত উপাদানকে লুপ না করে একটি সম্পূর্ণ অ্যারে ([কী] = মান) মুদ্রণের কোনও উপায় আছে কি?

ধরুন আমি কিছু উপাদান দিয়ে একটি অ্যারে তৈরি করেছি:

declare -A array
array=([a1]=1 [a2]=2 ... [b1]=bbb ... [f500]=abcdef)

আমি পুরো অ্যারে দিয়ে মুদ্রণ করতে পারেন

for i in "${!array[@]}"
do
echo "${i}=${array[$i]}"
done

যাইহোক, মনে হচ্ছে বাশ ইতিমধ্যে জানে কীভাবে কী ${!array[@]}এবং মান উভয় "অ্যারে" সমস্ত অ্যারে উপাদান পেতে হয় ${array[@]}

লুপ ছাড়াই এই তথ্যটি প্রিন্ট করার কোনও উপায় আছে?

সম্পাদনা:
typeset -p arrayকি!
তবে আমি একক প্রতিস্থাপনে উপসর্গ এবং প্রত্যয় উভয়ই মুছে ফেলতে পারি না:

a="$(typeset -p array)"
b="${a##*(}"
c="${b%% )*}"

আউটপুটের কেবল কী = মান অংশটি / প্রিন্ট করার কোনও ক্লিনার উপায় আছে?

উত্তর:


15

আমি মনে করি আপনি সেখানে দুটি ভিন্ন জিনিস জিজ্ঞাসা করছেন।

লুপ ছাড়াই এই তথ্যটি প্রিন্ট করার কোনও উপায় আছে?

হ্যাঁ, তবে তারা কেবল লুপটি ব্যবহার করার মতো ভাল নয়।

আউটপুটের কেবল কী = মান অংশটি / প্রিন্ট করার কোনও ক্লিনার উপায় আছে?

হ্যাঁ, forলুপ এটির সুবিধাগুলি রয়েছে যে এটির জন্য বাহ্যিক প্রোগ্রামের প্রয়োজন হয় না, সরল হয় এবং বিস্মিত না করে সঠিক আউটপুট ফর্ম্যাটটিকে নিয়ন্ত্রণ করা বরং আরও সহজ করে তোলে।


declare -p( typeset -p) এর আউটপুট হ্যান্ডেল করার চেষ্টা করে এমন যে কোনও সমাধানের সাথে ডিল করতে হবে) ক) বন্ধনী বা বন্ধনী যুক্ত ভেরিয়েবলের সম্ভাবনা, খ) declare -pশেলটির জন্য আউটপুটকে বৈধ ইনপুট করার জন্য যে উদ্ধৃতি যুক্ত করতে হবে।

উদাহরণস্বরূপ, আপনার প্রসারিত b="${a##*(}"কিছু মান খায়, যদি কোনও কী / মানটিতে একটি খোলার প্রথম বন্ধনী থাকে। এটি কারণ আপনি ব্যবহার করেছেন ##যা দীর্ঘতম উপসর্গটি সরিয়ে দেয় । একই জন্য c="${b%% )*}"। যদিও আপনি অবশ্যই declareআরও সঠিকভাবে মুদ্রিত বয়লারপ্লেটের সাথে মেলাতে পারতেন , আপনি যদি এখনও সমস্ত উদ্ধৃতি না চান তা পেতে আপনার একটি কঠিন সময় লাগবে।

আপনার প্রয়োজন না হলে এটি খুব সুন্দর দেখাচ্ছে না।

$ declare -A array=([abc]="'foobar'" [def]='"foo bar"')
$ declare -p array
declare -A array='([def]="\"foo bar\"" [abc]="'\''foobar'\''" )'

সঙ্গে forলুপ, এটা হিসাবে আপনি চান আউটপুট ফরম্যাট চয়ন করা আরো সহজ:

# without quoting
$ for x in "${!array[@]}"; do printf "[%s]=%s\n" "$x" "${array[$x]}" ; done
[def]="foo bar"
[abc]='foobar'

# with quoting
$ for x in "${!array[@]}"; do printf "[%q]=%q\n" "$x" "${array[$x]}" ; done
[def]=\"foo\ bar\"
[abc]=\'foobar\'

সেখান থেকে অন্যথায় আউটপুট ফর্ম্যাটটি পরিবর্তন করা সহজ (অন্যদিকে কীটি বন্ধনীগুলি সরিয়ে ফেলুন, সমস্ত কী / মান জোড়া একক লাইনে রাখুন ...)। আপনার যদি শেল নিজেই ছাড়া অন্য কোনও কিছুর উদ্ধৃতি দরকার হয়, আপনার এখনও এটি নিজের দ্বারা করা দরকার, তবে কমপক্ষে আপনার কাজ করার জন্য কাঁচা ডেটা থাকতে হবে। (যদি আপনার কী বা মানগুলিতে নতুন লাইন থাকে তবে আপনার সম্ভবত কিছু উদ্ধৃতি প্রয়োজন)

বর্তমান বাশ (৪.৪, আমার মনে হয়) এর সাহায্যে আপনি এর printf "[%s]=%s" "${x@Q}" "${array[$x]@Q}"পরিবর্তে ব্যবহার করতে পারেন printf "%q=%q"। এটি কিছুটা সুন্দর উদ্ধৃতিযুক্ত ফর্ম্যাট তৈরি করে, তবে অবশ্যই মনে রাখতে হবে আরও কিছু কাজ a (এবং এটি @অ্যারের কী হিসাবে কর্নার কেসের %qউদ্ধৃতি দেয় , যা উদ্ধৃতি দেয় না))

যদি লুপটি লিখতে খুব ক্লান্ত মনে হয় তবে এটি কোথাও একটি ফাংশন সংরক্ষণ করুন (এখানে উদ্ধৃতি না দিয়ে):

printarr() { declare -n __p="$1"; for k in "${!__p[@]}"; do printf "%s=%s\n" "$k" "${__p[$k]}" ; done ;  }  

এবং তারপরে এটি ব্যবহার করুন:

$ declare -A a=([a]=123 [b]="foo bar" [c]="(blah)")
$ printarr a
a=123
b=foo bar
c=(blah)

ইনডেক্সড অ্যারেগুলির সাথেও কাজ করে:

$ b=(abba acdc)
$ printarr b
0=abba
1=acdc

নোট করুন যে আপনার printf ...%q...বৈকল্পিকের আউটপুটটি শেলের পুনর্নির্মাণের জন্য উপযুক্ত নয় যদি অ্যারেতে একটি @কী থাকে কারণ% q এর উদ্ধৃতি না দেয় এবং a=([@]=value)এটি একটি সিনট্যাক্স ত্রুটি হয় bash
স্টাফেন চেজেলাস

স্পষ্টতঃ @ স্টাফেনচাজেলাস "${x@Q}"এটিও উদ্ধৃত করে, যেহেতু এটি সমস্ত স্ট্রিংয়ের উদ্ধৃতি দেয় (এবং আরও সুন্দর দেখায়)। যে ব্যবহার সম্পর্কে একটি নোট যুক্ত।
ইল্কাচ্চু

হ্যাঁ, ম্যাক্স থেকে অনুলিপি করা হয়েছে। এখনও অন্যরকম আকৃতির অপারেটর যা বেশিরভাগের সাথে একত্রিত করা যায় না। আবার, zshএর পরিবর্তনশীল প্রসারণের পতাকাগুলি দেখুন (এটি আবার দশকের দশক ধরে বাশের পূর্বাভাস দেয় এবং যার সাহায্যে আপনি উদ্ধৃতি শৈলীটি চয়ন করতে পারেন: design {(q) var}, $ {(qq) var} ...) আরও ভাল ডিজাইনের জন্য। বাশের এমকেএসের মতো একই সমস্যা রয়েছে যে এটি খালি স্ট্রিংটি উদ্ধৃত করে না (যেমন কোনও সমস্যা যেমন বাশ খালি কী সমর্থন করে না) not এছাড়াও, একক উদ্ধৃতি ( কিছু মানের জন্য ${var@Q}রিসর্ট $'...') ব্যতীত অন্য শৈলীর উদ্ধৃতিগুলি ব্যবহার করার সময় কোডটি একই লোকালে পুনরায় সংযুক্ত হওয়া গুরুত্বপূর্ণ।
স্টাফেন চেজেলাস

@ স্টাফেনচাজেলাস, আমার মনে হয় আপনি একটি সেট না করে মান বলতে চান, খালি স্ট্রিং নয়? ( x=; echo "${x@Q}"দিতে না '', unset x; echo "${x@Q}"কিছুই দেয়।) ব্যাশ এর @Qপছন্দ করা বলে মনে হয় $'\n'একটি আক্ষরিক সম্পর্কে newline, যা আসলে কিছু পরিস্থিতিতে ভাল হতে পারে ধরে (কিন্তু আমি বলতে পারবো না অন্যেরা কী পছন্দ করা)। অবশ্যই একটি পছন্দ আছে খারাপ হবে না।
ইল্কাচ্চু

ওহ হ্যাঁ দুঃখিত, আমি এটি বুঝতে পারি নি। এটি তখন মাক্স থেকে পার্থক্য। $'...'সিনট্যাক্স জিনিস একটি সম্ভাব্য সমস্যার মত হল LC_ALL=zh_HK.big5hkscs bash -c 'a=$'\''\n\u3b1'\''; printf "%s\n" "${a@Q}"'যা আউটপুট $'\n<0xa3><0x5c>'এবং 0x5cএকা ব্যাকস্ল্যাশ, তাই আপনি একটি সমস্যা আছে চাই যদি সেই উদ্ধৃতি একটি ভিন্ন লোকেল ব্যাখ্যা করা হয়।
স্টাফেন চেজেলাস

9
declare -p array
declare -A array='([a2]="2" [a1]="1" [zz]="Hello World" [b1]="bbb" [f50]="abcd" )'

2 কাঁটাচামচ

হয়তো এই:

printf "%s\n" "${!array[@]}"
a2
a1
f50
zz
b1

printf "%s\n" "${array[@]}"
2
1
abcd
Hello World
bbb

printf "%s\n" "${!array[@]}" "${array[@]}" | pr -2t
a2                              2
a1                              1
f50                             abcd
zz                              Hello World
b1                              bbb

3 কাঁটাচামচ

অথবা এটা:

paste -d= <(printf "%s\n" "${!array[@]}") <(printf "%s\n" "${array[@]}")
a2=2
a1=1
f50=abcd
zz=Hello World
b1=bbb

কাঁটাচামচ নেই

তুলনা করা

for i in "${!array[@]}";do printf "%s=%s\n" "$i" "${array[$i]}";done
a2=2
a1=1
f50=abcd
zz=Hello World
b1=bbb

ফাঁসি সময় তুলনা

শেষ বাক্য গঠন যেমন কাঁটাচামচ ব্যবহার করে না, সেগুলি দ্রুত হতে পারে:

time printf "%s\n" "${!array[@]}" "${array[@]}" | pr -2t | wc
      5      11      76
real    0m0.005s
user    0m0.000s
sys     0m0.000s

time paste -d= <(printf "%s\n" "${!array[@]}") <(printf "%s\n" "${array[@]}") | wc
      5       6      41
real    0m0.008s
user    0m0.000s
sys     0m0.000s

time for i in "${!array[@]}";do printf "%s=%s\n" "$i" "${array[$i]}";done | wc
      5       6      41
real    0m0.002s
user    0m0.000s
sys     0m0.001s

অ্যারে বড় হয়ে গেলে তবে এই নিশ্চয়তা সত্য হয় না; কাঁটাচামচ হ্রাস যদি ছোট প্রক্রিয়ার জন্য দক্ষ হয় তবে ডেডিকেটেড সরঞ্জামগুলি ব্যবহার করা বড় প্রক্রিয়ার জন্য আরও কার্যকর।

for i in {a..z}{a..z}{a..z};do array[$i]=$RANDOM;done


time printf "%s\n" "${!array[@]}" "${array[@]}" | pr -2t | wc
  17581   35163  292941
real    0m0.150s
user    0m0.124s
sys     0m0.036s

time paste -d= <(printf "%s\n" "${!array[@]}") <(printf "%s\n" "${array[@]}") | wc
  17581   17582  169875
real    0m0.140s
user    0m0.000s
sys     0m0.004s

time for i in "${!array[@]}";do printf "%s=%s\n" "$i" "${array[$i]}";done | wc
  17581   17582  169875
real    0m0.312s
user    0m0.268s
sys     0m0.076s

মন্তব্য

যেহেতু উভয় ( কাঁটাযুক্ত ) সমাধানগুলি সারিবদ্ধতা ব্যবহার করে , কোনও ভেরিয়েবলটিতে একটি নতুন লাইন থাকলে সেগুলির কোনওটিই কাজ করবে না । এই ক্ষেত্রে, একমাত্র উপায় forলুপ।


চতুর খুঁজছেন, উভয় উপায় একটি চেয়ে কম দক্ষ for। যা সত্যিই লজ্জাজনক।
স্যাটাস কাতসুরা

@ স্যাটোক্যাটসুর আমি সম্মত, তবে যদি ধীর হয় তবে সিনট্যাক্স ব্যবহার করে prখাটো করা যায় ... আমি prসিনট্যাক্স ধীরে ধীরে স্থির হওয়ার বিষয়ে নিশ্চিত নই , এমনকি বড় অ্যারে দিয়েও!
এফ। হাউরি

2
@ মনিম্যাক্স কারণ এটি সঠিক ফলাফল দেয় না (একই উপাদানগুলি, ভুল ক্রম)। আপনি জিপ অ্যারে প্রয়োজন চাই ${!array[@]}এবং ${array[@]}প্রথম যে কাজ করার জন্য।
স্যাটাস কাতসুরা

1
যে শেষ স্নিপেট সঙ্গে pasteহয় আর চেয়ে forপ্রশ্ন এক লাইন লেখা লুপ for i in "${!array[@]}"; do echo "$i=${array[$i]}" ; done, কিন্তু দুই subshells এবং একটি বহিস্থিত প্রোগ্রাম প্রয়োজন। কেমন সুন্দর? সঙ্গে সমাধান prএছাড়াও বিরতি যদি যেমন আউটপুট পৃষ্ঠা নম্বর দেওয়া করার চেষ্টা করে, অনেক উপাদান। আপনার এমন কিছু ব্যবহার করা দরকার | pr -2t -l"${#array[@]}"যা সাধারণ লুপের তুলনায় মনে রাখা শক্ত হতে শুরু করে এবং তার থেকেও এটি দীর্ঘ।
ইলকচাচু

1
ইন bash, cmd1 | cmd2অর্থ 2 কাঁটাচামচ, এমনকি যদি সেমিডি 1 বা সেমিডি 2 বা উভয়ই অন্তর্নির্মিত।
স্টাফেন চেজেলাস

2

আপনি যদি আরও ভাল এসোসিয়েটিভ অ্যারে সমর্থন সহ একটি শেল খুঁজছেন, চেষ্টা করুন zsh

ইন zsh(যেখানে মিশুক অ্যারে ksh93 এবং 2009 ব্যাশ জন্য 1993 তুলনায় 1998 সালে যোগ করা হয় নি), $varবা ${(v)var}(অ-খালি) বিস্তৃতি মান হ্যাশ এর ${(k)var}(অ-খালি) কি-সংকলন (একই আদেশ) এর, এবং ${(kv)var}উভয় কী এবং মানগুলি।

অ্যারেগুলির মতো খালি মানগুলি সংরক্ষণ করার জন্য, আপনাকে @পতাকাটি উদ্ধৃত করতে এবং ব্যবহার করতে হবে ।

সুতরাং কীগুলি এবং মানগুলি মুদ্রণ করতে এটি কেবল বিষয়

printf '%s => %s\n' "${(@kv)var}"

যদিও সম্ভবত খালি হ্যাশ হিসাবে অ্যাকাউন্ট রয়েছে, আপনার করা উচিত:

(($#var)) &&  printf '%s => %s\n' "${(@kv)var}"

আরও মনে রাখবেন যে zsh ksh93'এর (অনুলিপি করা bash) এর চেয়ে অনেক বেশি সংবেদনশীল এবং দরকারী অ্যারে সংজ্ঞা বাক্য গঠন ব্যবহার করে :

typeset -A var
var=(k1 v1 k2 v2 '' empty '*' star)

যা সহযোগী অ্যারেগুলিকে অনুলিপি করা বা মার্জ করা অনেক সহজ করে তোলে:

var2=("${(@kv)var1}")
var3+=("${(@kv)var2}")
var4=("${@kv)var4}" "${(@kv)var5}")

(আপনি সহজেই কোনও লুপ ছাড়াই একটি হ্যাশ অনুলিপি করতে পারবেন না bashএবং নোট করুন যে bashবর্তমানে খালি কী বা NUL বাইট সহ কী / মানগুলি সমর্থন করে না)।

আরও দেখুন zshঅ্যারের বৈশিষ্ট্য রয়েছে যা আপনি সাধারণত মিশুক অ্যারে সঙ্গে কাজ করতে হবে zip করা:

keys=($(<keys.txt)) values=($(<values.txt))
hash=(${keys:^values})

1

যেহেতু টাইপসেট আপনি যা চান তা কেন কেবল তার আউটপুট সম্পাদনা করে না?

typeset -p array | sed s/^.*\(// | tr -d ")\'\""  | tr "[" "\n" | sed s/]=/' = '/

দেয়

a2 = 2  
a1 = 1  
b1 = bbb 

কোথায়

array='([a2]="2" [a1]="1" [b1]="bbb" )'

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


এই ধরণের পাইপলাইন অ্যারেটির কিছু কী বা মানগুলির পরিবর্তে আপনি পরিবর্তিত হচ্ছেন এমন অক্ষর যেমন প্যারেন্থিসিস, বন্ধনী বা কোটস ধারণ করে to আর একটি পাইপলাইন seds এবং trকরা একটি চেয়ে আরও অনেক সহজ নয় forসঙ্গে লুপ printf
ইলক্কাচু

এছাড়াও, আপনি কি জানেন যে trচরিত্র অনুসারে চরিত্রটি অনুবাদ করে, এটি স্ট্রিংগুলির সাথে মেলে না? tr "]=" " ="একটি স্থান এবং পরিবর্তিত "]" =একটি থেকে =অবস্থান নির্বিশেষে। সুতরাং আপনি সম্ভবত তিনটি trএক সাথে একত্রিত করতে পারে ।
ইলকচাচু

অ-বর্ণমালা সংক্রান্ত কিছু চরিত্রগুলি এটিকে ঘৃণা করছে about যাইহোক তাদের মোকাবেলায় যে কোনও কিছুই প্রবণতার অর্ডার পেয়ে যায় আরও জটিল এবং কম পাঠযোগ্য, যদি না থাকে তবে আপনার ডেটা ফিডে সেগুলি রাখার সত্যিই কোনও ভাল কারণ রয়েছে এবং আমি এখানে উপস্থিত হওয়ার আগেই ধরে নিয়েছি যে প্রশ্নটিতে আমি ধরেছি যে তারা ফিল্টার করে চলেছে। সর্বদা আপনার স্পষ্ট সতর্কতা অবধি থাকা উচিত। আমি এই পাইপলাইনগুলিকে আরও সহজ বলে মনে করি, উদাহরণস্বরূপ এবং ডিবাগিংয়ের উদ্দেশ্যে, কোনও প্রিন্টফ গ্লোব তুলনায় যা হয় নিখুঁতভাবে কাজ করে বা আপনার মুখে ফুঁসে ওঠে। এখানে আপনি প্রতি উপাদানটিতে একটি সাধারণ পরিবর্তন করেছেন, এটি পরীক্ষা করুন, তারপরে আরও 1 যুক্ত করুন।
নাদরেক

আমার খারাপ! আমার _ টিআর_ এবং _স_স সম্পূর্ণ মিশ্রিত হয়েছে! সর্বশেষ সম্পাদনায় স্থির।
নাদরেক 23'17

1

আরও একটি বিকল্প হ'ল সমস্ত ভেরিয়েবলের তালিকাভুক্ত করা এবং আপনি যেটি চান তার জন্য গ্রেপ।

set | grep -e '^aa='

আমি এটি ডিবাগিংয়ের জন্য ব্যবহার করি। আমি সন্দেহ করি যে এটি খুব পারফরম্যান্ট, যেহেতু এটি সমস্ত ভেরিয়েবলের তালিকা করে।

আপনি যদি প্রায়শই এটি করতেন তবে আপনি এটিকে এটির মতো একটি কার্য করতে পারেন:

aap() { set | grep -e "^$1="; }

দুর্ভাগ্যক্রমে যখন আমরা সময় ব্যবহার করে কর্মক্ষমতা পরীক্ষা করি:

$ time aap aa aa=([0]="abc") . real 0m0.014s user 0m0.003s sys 0m0.006s

অতএব, আপনি যদি এটি প্রায়শই করে থাকেন তবে আপনি @ এফ.হৌরির কোনও ফোরকস সংস্করণ চাইবেন কারণ এটি এত দ্রুত faster

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