আমি কীভাবে বাশের কোনও অ্যারে থেকে অনন্য মান পেতে পারি?


93

আমি এখানে প্রায় একই প্রশ্ন পেয়েছি ।

আমার মধ্যে একটি অ্যারে রয়েছে aa ab aa ac aa ad, ইত্যাদি রয়েছে Now এখন আমি এই অ্যারে থেকে সমস্ত অনন্য উপাদান নির্বাচন করতে চাই। ভেবেছিলেন, তারা অন্যান্য প্রশ্নে উল্লিখিত হিসাবে sort | uniqবা সাথে এটি সহজ হবে sort -u, তবে অ্যারেতে কিছুই পরিবর্তন হয়নি ... কোডটি হ'ল:

echo `echo "${ids[@]}" | sort | uniq`

আমি কি ভুল করছি?

উত্তর:


131

কিছুটা হ্যাকি, তবে এটি করা উচিত:

echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '

বাছাই করা অনন্য ফলাফলগুলি আবার অ্যারেতে সংরক্ষণ করতে অ্যারে নিয়োগটি করুন :

sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))

যদি আপনার শেল এইস্ট্রাস্ট্রিংগুলিকে সমর্থন করে ( bashতবে), আপনি echoএটি পরিবর্তন করে কোনও প্রক্রিয়া বাঁচাতে পারেন :

tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '

ইনপুট:

ids=(aa ab aa ac aa ad)

আউটপুট:

aa ab ac ad

ব্যাখ্যা:

  • "${ids[@]}"- শেল অ্যারেগুলির সাথে কাজ করার জন্য সিনট্যাক্স, এর অংশ হিসাবে ব্যবহার করা হবে echoবা এস্ট্রাস্ট্রিং হোক। @অংশ মানে হলো "অ্যারের মধ্যে সব উপাদান"
  • tr ' ' '\n'- সমস্ত স্পেসকে নতুন লাইনে রূপান্তর করুন। কারণ আপনার অ্যারে শেল দ্বারা একক লাইনের উপাদান হিসাবে ফাঁকা জায়গা দ্বারা পৃথক করা দেখা যায়; এবং কারণ সাজানটি আলাদা লাইনে ইনপুট হওয়ার প্রত্যাশা করে।
  • sort -u - শুধুমাত্র অনন্য উপাদানগুলি সাজান এবং ধরে রাখুন
  • tr '\n' ' ' - আমরা নতুন যুক্ত করা লাইনে আগের জায়গায় ফাঁকা স্থানগুলিতে রূপান্তর করুন।
  • $(...)- কমান্ড সাবস্টিটিউশন
  • পাশে: করণের tr ' ' '\n' <<< "${ids[@]}"আরও কার্যকর উপায়:echo "${ids[@]}" | tr ' ' '\n'

37
+1 কিছুটা সাশ্রয়ী: একটি নতুন অ্যারেতে ইউনিক উপাদানগুলি সঞ্চয় করুন:uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"
গ্লেন জ্যাকম্যান

নিঃসৃত! আপনি printf
বুঝতেও

4
+1 আমি নিশ্চিত নই যে এটি কোনও বিচ্ছিন্ন ঘটনা কিনা, তবে অনন্য আইটেমগুলিকে অ্যারেতে ফিরিয়ে দেওয়ার জন্য অতিরিক্ত বন্ধনী যেমন: প্রয়োজন হয় sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))। অতিরিক্ত বন্ধনী ছাড়া এটি স্ট্রিং হিসাবে এটি দিচ্ছিল।
whla

4
আপনি যদি উপাদানগুলির ক্রম পরিবর্তন করতে না চান তবে ... | uniq | ...পরিবর্তে ব্যবহার করুন ... | sort -u | ...
জেসি চিশল্ম

4
@ জেসি uniqকেবল একটানা ডুপ্লিকেটগুলি সরিয়ে দেয় । এই উত্তরের উদাহরণে, sorted_unique_idsমূলটির সাথে সমান হবে ids। অর্ডার সংরক্ষণের জন্য, চেষ্টা করুন ... | awk '!seen[$0]++'স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / 1444406/… দেখুন ।
রব কেনেডি

29

আপনি যদি বাশ সংস্করণ 4 বা ততোধিক চলমান করেন (যা লিনাক্সের কোনও আধুনিক সংস্করণে হওয়া উচিত) তবে আপনি মূল অ্যারের প্রতিটি মান সমন্বিত একটি নতুন এসোসিয়েটিভ অ্যারে তৈরি করে ব্যাশে অনন্য অ্যারে মান পেতে পারেন। এটার মতো কিছু:

$ a=(aa ac aa ad "ac ad")
$ declare -A b
$ for i in "${a[@]}"; do b["$i"]=1; done
$ printf '%s\n' "${!b[@]}"
ac ad
ac
aa
ad

এটি কাজ করে কারণ যে কোনও অ্যারে (সংঘবদ্ধ বা traditionalতিহ্যবাহী, কোনও ভাষায়), প্রতিটি কী কেবল একবার উপস্থিত হতে পারে। যখন forলুপ দ্বিতীয় মান আসে aaমধ্যে a[2], এটা মুছে ফেলা হয় b[aa], যা আসলে জন্য সেট করা হয় a[0]

নেটিভ ব্যাশ জিনিসগুলি পাইপ মত বাহ্যিক সরঞ্জাম ব্যবহার তুলনায় দ্রুততর হতে পারে sortএবং uniq, যদি আপনি awk, পাইথন, ইত্যাদি একটি অধিক শক্তিশালী ভাষা ব্যবহার যদিও বড় ডেটাসেট জন্য আপনাকে সম্ভবত ভাল পারফরম্যান্স দেখতে পাবেন

আপনি যদি আত্মবিশ্বাসী বোধ করেন তবে একাধিক যুক্তির জন্য এর ফর্ম্যাটটিকে পুনর্ব্যবহার করার ক্ষমতা forব্যবহার করে আপনি লুপটি এড়াতে পারবেন printf, যদিও এটির প্রয়োজন মনে হচ্ছে eval। (আপনি যদি ঠিক হয়ে থাকেন তবে এখনই পড়া বন্ধ করুন))

$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") )
$ declare -p b
declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )

এই সমাধানটির প্রয়োজনীয় কারণটি evalহ'ল শব্দ বিভাজনের আগে অ্যারের মানগুলি নির্ধারিত হয়। এর অর্থ হ'ল কমান্ড প্রতিস্থাপনের আউটপুট একক শব্দ হিসাবে বিবেচিত হয় কী = মান জোড়ার সেট না করে হয়।

এটি একটি সাব-শেল ব্যবহার করার সময় অ্যারের মানগুলি প্রক্রিয়া করতে এটি কেবল ব্যাশ বিল্টিন ব্যবহার করে। evalএকটি সমালোচিত চোখ দিয়ে আপনার ব্যবহার মূল্যায়ন নিশ্চিত হন । আপনি যদি 100% আত্মবিশ্বাসী না হন যে চ্পনার বা গ্লেন জ্যাকম্যান বা গ্রাইকাট আপনার কোডটিতে কোনও দোষ খুঁজে না পাবে, তবে পরিবর্তে লুপটি ব্যবহার করুন।


ত্রুটি উত্পাদন করে: এক্সপ্রেশন পুনরাবৃত্তি স্তর অতিক্রম করেছে
বেনুবার্ড

4
@ বেনুবার্ড - আপনি কি সম্ভবত আপনার টার্মিনাল বিষয়বস্তু পেস্টবিন করতে পারেন? এটি আমার পক্ষে নিখুঁতভাবে কাজ করে, তাই আমার সর্বোত্তম অনুমানটি হ'ল আপনি (1) একটি টাইপো পেয়েছেন, (2) বাশ (পুরানো সংস্করণ ভি 4-তে যোগ করা হয়েছে), বা (3) মহাজাগতিক ব্যাকগ্রাউন্ডের একটি হাস্যকর আকারে বিশাল আগমন আপনার প্রতিবেশীর বেসমেন্টের কোয়ান্টাম ব্ল্যাকহোল দ্বারা সৃষ্ট বিকিরণ, আপনার কম্পিউটারের মধ্যে সংকেতগুলির সাথে হস্তক্ষেপ সৃষ্টি করে।
ঘোটি

4
পারে না, যে কাজ করে না তাকে রাখবে না। তবে, আমি এখনই আপনার চালানোর চেষ্টা করেছি এবং এটি কাজ করেছে, তাই সম্ভবত মহাজাগতিক বিকিরণ জিনিস।
বেনুবার্ড

অনুমান করে যে এই উত্তরটি ব্যাশ ভি 4 (এসোসিয়েটিভ অ্যারে) ব্যবহার করে এবং যদি কেউ ব্যাশ ভি 3 এ চেষ্টা করে তবে এটি কাজ করবে না (সম্ভবত @ বেনুবার্ড কী দেখেছিল)। ব্যাশ v3 এর এখনো অনেক envs মধ্যে ডিফল্ট
nhed

4
@ নেড, পয়েন্ট নেওয়া হয়েছে। আমি দেখতে পাচ্ছি যে আমার আপ টু ডেট ইয়োসেমাইট ম্যাকবুকের বেসে একই সংস্করণ রয়েছে, যদিও আমি ম্যাকপোর্টগুলি থেকে ভি 4 ইনস্টল করেছি। এই প্রশ্নটিকে "লিনাক্স" ট্যাগ করা হয়েছে, তবে প্রয়োজনীয়তার বিষয়টি উল্লেখ করার জন্য আমি আমার উত্তর আপডেট করেছি।
ঘোটি

18

আমি বুঝতে পেরেছি এর উত্তর ইতিমধ্যে দেওয়া হয়েছিল, তবে এটি অনুসন্ধানের ফলাফলগুলিতে বেশ উচ্চতর প্রদর্শিত হয়েছিল এবং এটি কারওর পক্ষে সহায়তা করতে পারে।

printf "%s\n" "${IDS[@]}" | sort -u

উদাহরণ:

~> IDS=( "aa" "ab" "aa" "ac" "aa" "ad" )
~> echo  "${IDS[@]}"
aa ab aa ac aa ad
~>
~> printf "%s\n" "${IDS[@]}" | sort -u
aa
ab
ac
ad
~> UNIQ_IDS=($(printf "%s\n" "${IDS[@]}" | sort -u))
~> echo "${UNIQ_IDS[@]}"
aa ab ac ad
~>

4
অ্যারে ঠিক করার জন্য আমাকে এটি করতে বাধ্য করা হয়েছিল: ids=(ab "a a" ac aa ad ac aa);IFS=$'\n' ids2=(`printf "%s\n" "${ids[@]}" |sort -u`)তাই আমি IFS=$'\n'@gniourf_gniourf
কুম্ভ শক্তি দ্বারা

আমাকেও ব্যাকআপ নিতে হয়েছিল এবং, কমান্ডের পরে, আইএফএসের মান পুনরুদ্ধার করতে হবে! বা এটি অন্য জিনিসগুলিতে গোলমাল করে ..
কুম্ভ শক্তি পাওয়ার

@ জেটস এটি গ্রহণযোগ্য উত্তর হওয়া উচিত কারণ এটি কেবলমাত্র দুটি কমান্ড ব্যবহার করে, কোনও লুপ নেই, কোনও ফল নেই এবং এটি সবচেয়ে কমপ্যাক্ট সংস্করণ।
মিগ্লুট্ট

4
@ অ্যাকুরিয়াস পাওয়ার যত্নশীল, আপনি মূলত: করছেন IFS=$'\n'; ids2=(...), যেহেতু ভেরিয়েবল অ্যাসাইনমেন্টের আগে অস্থায়ী নিয়োগ সম্ভব নয়। এর পরিবর্তে এই নির্মাণ ব্যবহার করুন: IFS=$'\n' read -r -a ids2 <<<"$(printf "%s\n" "${ids[@]}" | sort -u)"
ইয়েতি

13

যদি আপনার অ্যারে উপাদানগুলির মধ্যে সাদা স্থান বা অন্য কোনও শেল বিশেষ অক্ষর থাকে (এবং আপনি কী নিশ্চিত যে তারা তা নয়?) তবে সবার আগে ক্যাপচার করতে (এবং আপনার সর্বদা এটি করা উচিত) আপনার অ্যারেটিকে ডাবল কোটে প্রকাশ করুন! যেমন "${a[@]}"। বাশ আক্ষরিক অর্থে এটি "পৃথক যুক্তিতে প্রতিটি অ্যারে উপাদান" হিসাবে ব্যাখ্যা করবে । বাশের মধ্যে এটি কেবল সর্বদা, সর্বদা কাজ করে।

তারপরে, বাছাই করা (এবং অনন্য) অ্যারে পেতে আমাদের এটিকে রূপান্তর করতে হবে যা বোঝা যায় এবং এটি আবার ব্যাশ অ্যারের উপাদানগুলিতে রূপান্তর করতে সক্ষম হন। এটিই আমি নিয়ে এসেছি সেরা:

eval a=($(printf "%q\n" "${a[@]}" | sort -u))

দুর্ভাগ্যক্রমে, এটি শূন্য অ্যারের বিশেষ ক্ষেত্রে ব্যর্থ হয়, খালি অ্যারেটিকে 1 টি খালি উপাদানের অ্যারে রূপান্তরিত করে (কারণ প্রিন্টফের 0 টি আর্গুমেন্ট ছিল তবে এখনও এটি মুদ্রণ করে যেমন এটির একটি খালি যুক্তি রয়েছে - ব্যাখ্যা দেখুন)। সুতরাং আপনি এটি একটি বা যদি কিছু ধরতে হবে।

ব্যাখ্যা: প্রিন্টফের জন্য% কিউ ফর্ম্যাটটি "শেল পলায়ন" মুদ্রিত আর্গুমেন্টের ঠিক ঠিক এমনভাবে যেমন বাশ এভাল জাতীয় কিছুতে পুনরুদ্ধার করতে পারে! যেহেতু প্রতিটি উপাদান মুদ্রিত শেলটি তার নিজস্ব লাইনে ছড়িয়ে পড়েছে, উপাদানগুলির মধ্যে একমাত্র বিভাজকটি হ'ল নিউলাইন এবং অ্যারে অ্যাসাইনমেন্টটি প্রতিটি রেখাকে একটি উপাদান হিসাবে গ্রহণ করে, পালিয়ে যাওয়া মানগুলিকে আক্ষরিক পাঠ্যে ভাগ করে।

যেমন

> a=("foo bar" baz)
> printf "%q\n" "${a[@]}"
'foo bar'
baz
> printf "%q\n"
''

বিভাজক প্রতিটি অ্যারের মধ্যে ফিরে যাচ্ছে পালাতে স্ট্রিপ প্রয়োজন।


এটি আমার জন্য কাজ করা একমাত্র কোড কারণ আমার স্ট্রিংয়ের অ্যারেতে ফাঁকা জায়গা ছিল। % কি কি কৌশলটি করেছে। ধন্যবাদ :)
সোমাইয়া কুম্বের

এবং যদি আপনি উপাদানগুলির ক্রম পরিবর্তন করতে না চান তবে এর uniqপরিবর্তে ব্যবহার করুন sort -u
জেসি চিশল্ম

নোট করুন যে uniqঅরসোর্টড তালিকাগুলিতে সঠিকভাবে কাজ করে না, তাই এটি সর্বদা সাথে মিশ্রণে ব্যবহার করা আবশ্যক sort
জিন পল

অচিরাচরিত তালিকায় থাকা ইউনিক ক্রমাগত সদৃশগুলি সরিয়ে ফেলবে । এটি অভ্যন্তরীণ অন্য কিছু দ্বারা পৃথক অভিন্ন তালিকার উপাদানগুলি সরাবে না। ইউনিট প্রত্যাশিত ডেটা এবং মূল শৃঙ্খলা বজায় রাখার আকাঙ্ক্ষার উপর নির্ভর করে যথেষ্ট কার্যকর হতে পারে।
ভ্যানট্র্যাপ

10

'বাছাই' একটি লুপের আউটপুট অর্ডার করতে ব্যবহার করা যেতে পারে:

for i in ${ids[@]}; do echo $i; done | sort

এবং "-u" দিয়ে নকলগুলি মুছে ফেলুন:

for i in ${ids[@]}; do echo $i; done | sort -u

অবশেষে আপনি অনন্য উপাদানগুলির সাহায্যে আপনার অ্যারে ওভাররাইট করতে পারেন:

ids=( `for i in ${ids[@]}; do echo $i; done | sort -u` )

এবং যদি আপনি কী বাকী থাকে তার ক্রমটি পরিবর্তন করতে না চান, আপনার দরকার নেই:ids=( `for i in ${ids[@]}; do echo $i; done | uniq` )
জেসি চিশলম

3

এটি একটি অর্ডারও সংরক্ষণ করবে:

echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'

এবং অনন্য মানগুলির সাথে মূল অ্যারেটি সংশোধন করতে:

ARRAY=($(echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'))

ব্যবহার করবেন না uniq। এটি বাছাই করা দরকার, যেখানে সন্ত্রস্ততা নেই, এবং ইনপুটটি সাজাতে না পারলে এই উত্তরটির উদ্দেশ্যটি ক্রম সংরক্ষণ করা।
বুকজোর

2

অনন্য মান সমন্বিত একটি নতুন অ্যারে তৈরি করতে, আপনার অ্যারেটি খালি নেই তা নিশ্চিত করুন তবে নিম্নলিখিতগুলির মধ্যে একটি করুন:

সদৃশ এন্ট্রিগুলি সরান (বাছাই সহ)

readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | sort -u)

সদৃশ এন্ট্রি সরান (বাছাই ছাড়াই)

readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | awk '!x[$0]++')

সতর্কতা: এর মতো কিছু করার চেষ্টা করবেন না NewArray=( $(printf '%s\n' "${OriginalArray[@]}" | sort -u) )। এটি স্পেসে ভাঙ্গবে।


সদৃশ এন্ট্রি সরান (বাছাই ছাড়াই) পরিবর্তন sort -uকরা বাদে (সাজানোর সাথে) ঠিক যেমন হয় uniq
জেসি চিশল্ম

@ জেসি চিসলম uniqকেবল সংলগ্ন ডুপ্লিকেট লাইনগুলিকে একীভূত করেছে, সুতরাং এটি এর মতো নয় awk '!x[$0]++'
ছয়

@ জেসি চিশলম বিভ্রান্তিকর মন্তব্য মুছতে দয়া করে।
বুকজোর

2

বিড়াল সংখ্যা। txt

1 2 3 4 4 3 2 5 6

কলামে প্রিন্ট করুন: cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}'

1
2
3
4
4
3
2
5
6

সদৃশ রেকর্ডগুলি সন্ধান করুন: cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}' |awk 'x[$0]++'

4
3
2

সদৃশ রেকর্ড প্রতিস্থাপন করুন: cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}' |awk '!x[$0]++'

1
2
3
4
5
6

কেবল ইউনিক রেকর্ডগুলি সন্ধান করুন: cat number.txt | awk '{for(i=1;i<=NF;i++) print $i|"sort|uniq -u"}

1
5
6


1

আপনি যদি এমন কোনও সমাধান চান যা কেবল ব্যাশ ইন্টার্নাল ব্যবহার করে, আপনি একটি সহযোগী অ্যারেতে মানগুলি কী হিসাবে সেট করতে পারেন এবং তারপরে কীগুলি বের করতে পারেন:

declare -A uniqs
list=(foo bar bar "bar none")
for f in "${list[@]}"; do 
  uniqs["${f}"]=""
done

for thing in "${!uniqs[@]}"; do
  echo "${thing}"
done

এই আউটপুট হবে

bar
foo
bar none

আমি কেবল লক্ষ্য করেছি যে এটি মূলত উপরের @ ঘোটিস জবাব হিসাবে সমান, তার সমাধান ব্যতীত ফাঁকা জায়গাগুলির তালিকা আইটেমগুলিতে গ্রহণ করে না except
rln

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

1

এম্বেড করা শ্বেত স্পেসের সাথে কাজ করার জন্য আরেকটি বিকল্প হ'ল এটি বাতিল করে দেওয়া, তার সাথে printfআলাদা করা sort, তারপরে একটি অ্যারেতে প্যাক করতে একটি লুপ ব্যবহার করুন:

input=(a b c "$(printf "d\ne")" b c "$(printf "d\ne")")
output=()

while read -rd $'' element
do 
  output+=("$element")
done < <(printf "%s\0" "${input[@]}" | sort -uz)

এর শেষে, inputএবং outputপছন্দসই মানগুলি অন্তর্ভুক্ত থাকে (সরবরাহিত ক্রমটি গুরুত্বপূর্ণ নয়):

$ printf "%q\n" "${input[@]}"
a
b
c
$'d\ne'
b
c
$'d\ne'

$ printf "%q\n" "${output[@]}"
a
b
c
$'d\ne'


0

ফাইলটিতে প্রথম কলামের জন্য ইউনিট মান পেতে এটি চেষ্টা করুন

awk -F, '{a[$1];}END{for (i in a)print i;}'

-3
# Read a file into variable
lines=$(cat /path/to/my/file)

# Go through each line the file put in the variable, and assign it a variable called $line
for line in $lines; do
  # Print the line
  echo $line
# End the loop, then sort it (add -u to have unique lines)
done | sort -u
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.