উত্তর:
আপনার আসলে এত বেশি কোডের দরকার নেই:
IFS=$'\n' sorted=($(sort <<<"${array[*]}"))
unset IFS
উপাদানগুলিতে হোয়াইটস্পেস সমর্থন করে (যতক্ষণ না এটি কোনও নতুন লাইন নয়) এবং বাশ 3.x এ কাজ করে।
উদাহরণ:
$ array=("a c" b f "3 5")
$ IFS=$'\n' sorted=($(sort <<<"${array[*]}")); unset IFS
$ printf "[%s]\n" "${sorted[@]}"
[3 5]
[a c]
[b]
[f]
নোট: @sorontar হয়েছে উল্লেখ করে যত্ন প্রয়োজন বোধ করা হয় যদি উপাদানের যেমন ওয়াইল্ডকার্ড ধারণ *
বা ?
:
সাজানো = ($ (...)) অংশটি "বিভক্ত এবং গ্লোব" অপারেটরটি ব্যবহার করছে। আপনার গ্লোব বন্ধ করা উচিত:
set -f
বাset -o noglob
বাshopt -op noglob
অ্যারের মতো কোনও উপাদান*
ফাইলের তালিকায় প্রসারিত হবে।
এই ক্রমটি ঘটে এমন ছয়টি পরিণতি ফলাফল:
IFS=$'\n'
"${array[*]}"
<<<
sort
sorted=($(...))
unset IFS
IFS=$'\n'
এটি আমাদের অপারেশনের একটি গুরুত্বপূর্ণ অংশ যা 2 এবং 5 এর ফলাফলকে নিম্নলিখিত উপায়ে প্রভাবিত করে:
প্রদত্ত:
"${array[*]}"
এর প্রথম চরিত্রের দ্বারা সীমিত প্রতিটি উপাদানগুলিতে প্রসারিত হয় IFS
sorted=()
এর প্রতিটি চরিত্রকে বিভক্ত করে উপাদান তৈরি করে IFS
IFS=$'\n'
জিনিসগুলি সেট আপ করে যাতে উপাদানগুলি ডিলিমিটার হিসাবে একটি নতুন লাইন ব্যবহার করে প্রসারিত হয় এবং পরে এমনভাবে তৈরি করা হয় যাতে প্রতিটি লাইন একটি উপাদান হয়ে যায়। (অর্থাত্ একটি নতুন লাইনে বিভক্ত করা))
একটি নতুন লাইনের মাধ্যমে সীমানা নির্ধারণ গুরুত্বপূর্ণ কারণ এটি কীভাবে sort
কাজ করে (প্রতি লাইনে বাছাই করা)। কেবলমাত্র একটি নতুন লাইন দ্বারা বিভক্ত করা গুরুত্বপূর্ণ হিসাবে গুরুত্বপূর্ণ নয়, তবে ফাঁকা বা ট্যাবযুক্ত উপাদানগুলি সংরক্ষণ করা দরকার serve
এর ডিফল্ট মান IFS
হ'ল একটি স্থান , একটি ট্যাব , তার পরে একটি নতুন লাইন থাকে এবং এটি আমাদের ক্রিয়াকলাপের জন্য অযোগ্য।
sort <<<"${array[*]}"
অংশ<<<
, এখানে স্ট্রিং বলা হয় "${array[*]}"
, উপরে বর্ণিত হিসাবে এর প্রসারণ গ্রহণ করে এবং এর স্ট্যান্ডার্ড ইনপুটটিতে ফিড দেয় sort
।
আমাদের উদাহরণ সহ, sort
এই নিম্নলিখিত স্ট্রিং খাওয়ানো হয়:
a c
b
f
3 5
sort
প্রকারভেদ থেকে , এটি উত্পাদন করে:
3 5
a c
b
f
sorted=($(...))
অংশ$(...)
অংশ বলা কমান্ড প্রতিকল্পন , তার বিষয়বস্তু (ঘটায় sort <<<"${array[*]}
যখন ফলে গ্রহণ,) একটি স্বাভাবিক কমান্ড হিসাবে চালানোর জন্য মান আউটপুট আক্ষরিক যেমন যায় কোথায় কি কখনো $(...)
ছিল না।
আমাদের উদাহরণে, এটি কেবল লেখার অনুরূপ কিছু তৈরি করে:
sorted=(3 5
a c
b
f
)
sorted
তারপরে একটি অ্যারেতে পরিণত হয় যা প্রতিটি নতুন লাইনে এই আক্ষরিককে বিভক্ত করে তৈরি করা হয়।
unset IFS
এটি IFS
ডিফল্ট মানটির মানটিকে পুনরায় সেট করে এবং এটি কেবলমাত্র ভাল অনুশীলন।
এটি IFS
আমাদের স্ক্রিপ্টের উপর নির্ভর করে যে কোনও কিছুতেই আমরা সমস্যা সৃষ্টি না করি তা নিশ্চিত করা । (অন্যথায় আমাদের মনে রাখতে হবে যে আমরা চারপাশে জিনিসগুলি স্যুইচ করেছি - এমন কিছু যা জটিল স্ক্রিপ্টগুলির জন্য অযৌক্তিক হতে পারে))
IFS
এটি আপনার উপাদানগুলিকে সামান্য টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো করে যদি এটিতে একটি নির্দিষ্ট ধরণের সাদা অংশ থাকে। ভাল; নিখুঁত নয় :-)
unset IFS
প্রয়োজনীয়? আমি ভেবেছিলাম IFS=
কোনও কমান্ডের প্রিপেন্ডিং কেবলমাত্র সেই কমান্ডের পরিবর্তনটি বাদ দিয়েছে, তার পরে স্বয়ংক্রিয়ভাবে তার আগের মানটিতে ফিরে আসবে।
sorted=()
এটি একটি কমান্ড নয় বরং একটি দ্বিতীয় ভেরিয়েবল অ্যাসাইনমেন্ট।
আসল প্রতিক্রিয়া:
array=(a c b "f f" 3 5)
readarray -t sorted < <(for a in "${array[@]}"; do echo "$a"; done | sort)
আউটপুট:
$ for a in "${sorted[@]}"; do echo "$a"; done
3
5
a
b
c
f f
উল্লেখ্য মান এই সংস্করণে কাটিয়ে ওঠার যে (বিশেষ অক্ষর বা সাদা ব্যবধান সমন্বিত ছাড়া নতুন লাইন)
দ্রষ্টব্য পাঠক বাশ 4+ এ সমর্থিত।
@ ডিমিতের পরামর্শের ভিত্তিতে সম্পাদনা করুন আমি এটি এতে আপডেট করেছি:
readarray -t sorted < <(printf '%s\0' "${array[@]}" | sort -z | xargs -0n1)
যা সঠিকভাবে এমবেড করা নিউলাইন চরিত্রগুলি সহ উপাদানগুলি বাছাই করার সুবিধাও রয়েছে । দুর্ভাগ্যবশত, যেমন সঠিকভাবে দ্বারা @ruakh এর মানে এই নয় হয়নি ফল সংকেত readarray
হবে সঠিক , কারণ readarray
ব্যবহার করার কোনও বিকল্প থাকে NUL
নিয়মিত পরিবর্তে নতুন লাইন লাইন বিভাজক হিসাবে।
readarray -t sorted < <(printf '%s\n' "${array[@]}" | sort)
sort -z
একটি দরকারী উন্নতি, আমি অনুমান করি যে -z
বিকল্পটি একটি জিএনইউ সাজানোর এক্সটেনশন।
sorted=(); while read -d $'\0' elem; do sorted[${#sorted[@]}]=$elem; done < <(printf '%s\0' "${array[@]}" | sort -z)
। এটি আপনার মধ্যে ব্যাশ ভি 4 এর পরিবর্তে ব্যাশ ভি 3 ব্যবহার করছে এমনটিও কাজ করে কারণ ব্যাশ ভি 3-তে রিডারের উপলব্ধ নেই।
<
) সঙ্গে মিলিত প্রক্রিয়া প্রতিকল্পন <(...)
। বা এটি স্বজ্ঞাতভাবে বলতে: কারণ (printf "bla")
এটি কোনও ফাইল নয়।
এখানে একটি খাঁটি বাশ কুইকোর্টের বাস্তবায়ন:
#!/bin/bash
# quicksorts positional arguments
# return is in array qsort_ret
qsort() {
local pivot i smaller=() larger=()
qsort_ret=()
(($#==0)) && return 0
pivot=$1
shift
for i; do
if (( i < pivot )); then
smaller+=( "$i" )
else
larger+=( "$i" )
fi
done
qsort "${smaller[@]}"
smaller=( "${qsort_ret[@]}" )
qsort "${larger[@]}"
larger=( "${qsort_ret[@]}" )
qsort_ret=( "${smaller[@]}" "$pivot" "${larger[@]}" )
}
যেমন ব্যবহার করুন
$ array=(a c b f 3 5)
$ qsort "${array[@]}"
$ declare -p qsort_ret
declare -a qsort_ret='([0]="3" [1]="5" [2]="a" [3]="b" [4]="c" [5]="f")'
এই প্রয়োগটি পুনরাবৃত্ত হয় ... সুতরাং এখানে একটি পুনরাবৃত্তি কোকসোর্ট:
#!/bin/bash
# quicksorts positional arguments
# return is in array qsort_ret
# Note: iterative, NOT recursive! :)
qsort() {
(($#==0)) && return 0
local stack=( 0 $(($#-1)) ) beg end i pivot smaller larger
qsort_ret=("$@")
while ((${#stack[@]})); do
beg=${stack[0]}
end=${stack[1]}
stack=( "${stack[@]:2}" )
smaller=() larger=()
pivot=${qsort_ret[beg]}
for ((i=beg+1;i<=end;++i)); do
if [[ "${qsort_ret[i]}" < "$pivot" ]]; then
smaller+=( "${qsort_ret[i]}" )
else
larger+=( "${qsort_ret[i]}" )
fi
done
qsort_ret=( "${qsort_ret[@]:0:beg}" "${smaller[@]}" "$pivot" "${larger[@]}" "${qsort_ret[@]:end+1}" )
if ((${#smaller[@]}>=2)); then stack+=( "$beg" "$((beg+${#smaller[@]}-1))" ); fi
if ((${#larger[@]}>=2)); then stack+=( "$((end-${#larger[@]}+1))" "$end" ); fi
done
}
উভয় ক্ষেত্রেই, আপনি যে ক্রমটি ব্যবহার করেন তা বদলাতে পারেন: আমি স্ট্রিং তুলনা ব্যবহার করেছি, তবে আপনি পাটিগণিত তুলনা ব্যবহার করতে পারেন, আর্ট ফাইল পরিবর্তনের সময় তুলনা করতে পারেন ইত্যাদি যথাযথ পরীক্ষাটি ব্যবহার করুন; আপনি এটিকে আরও জেনেরিক করে তুলতে পারেন এবং এটির প্রথম যুক্তিটি পরীক্ষা ফাংশন ব্যবহার হিসাবে ব্যবহার করতে পারেন, উদাহরণস্বরূপ,
#!/bin/bash
# quicksorts positional arguments
# return is in array qsort_ret
# Note: iterative, NOT recursive! :)
# First argument is a function name that takes two arguments and compares them
qsort() {
(($#<=1)) && return 0
local compare_fun=$1
shift
local stack=( 0 $(($#-1)) ) beg end i pivot smaller larger
qsort_ret=("$@")
while ((${#stack[@]})); do
beg=${stack[0]}
end=${stack[1]}
stack=( "${stack[@]:2}" )
smaller=() larger=()
pivot=${qsort_ret[beg]}
for ((i=beg+1;i<=end;++i)); do
if "$compare_fun" "${qsort_ret[i]}" "$pivot"; then
smaller+=( "${qsort_ret[i]}" )
else
larger+=( "${qsort_ret[i]}" )
fi
done
qsort_ret=( "${qsort_ret[@]:0:beg}" "${smaller[@]}" "$pivot" "${larger[@]}" "${qsort_ret[@]:end+1}" )
if ((${#smaller[@]}>=2)); then stack+=( "$beg" "$((beg+${#smaller[@]}-1))" ); fi
if ((${#larger[@]}>=2)); then stack+=( "$((end-${#larger[@]}+1))" "$end" ); fi
done
}
তাহলে আপনি এই তুলনা ফাংশন করতে পারেন:
compare_mtime() { [[ $1 -nt $2 ]]; }
আর ব্যবহার করুন:
$ qsort compare_mtime *
$ declare -p qsort_ret
বর্তমান ফোল্ডারে ফাইলগুলি পরিবর্তনের সময় অনুসারে বাছাই করতে (সর্বপ্রথম নতুন)।
বিঃদ্রঃ. এই ফাংশনগুলি খাঁটি বাশ! কোন বাহ্যিক ইউটিলিটি, এবং কোন সাবশেল! এগুলি আপনার কাছে থাকা যে কোনও মজাদার প্রতীক নিরাপদে রয়েছে (স্পেস, নিউলাইন অক্ষর, গ্লোব অক্ষর ইত্যাদি)।
sort
যথেষ্ট পরিমাণে সরবরাহ করা হয় তবে একটি sort
+ read -a
সমাধান চারপাশে দ্রুত শুরু হবে, বলুন, 20 টি আইটেম এবং ক্রমবর্ধমান এবং উল্লেখযোগ্যভাবে আপনি যে উপাদানগুলির সাথে লেনদেন করছেন তত দ্রুত। উদাহরণস্বরূপ, আমার শেষ-২০১২ আইম্যাকে ফিউশন ড্রাইভ সহ ওএসএক্স 10.11.1 চলছে: 100-উপাদান অ্যারে: সিএ 0.03 সেকেন্ড ( qsort()
) বনাম সিএ 0.005 সেকেন্ড ( sort
+ read -a
); 1000-উপাদান অ্যারে: সিএ। 0.375 সেকেন্ড ( qsort()
) বনাম সিএ 0.014 সেকেন্ড ( sort
+ read -a
)।
if [ "$i" -lt "$pivot" ]; then
দরকার ছিল অন্যথায় সমাধান করা "2" <"10" সত্য হয়ে গেছে। আমি এটিকে পসিক্স বনাম লিক্সোগ্রাফিক হিসাবে বিশ্বাস করি; অথবা সম্ভবত ইনলাইন লিঙ্ক ।
আপনার যদি অ্যারের উপাদানগুলিতে বিশেষ শেল অক্ষরগুলি হ্যান্ডেল করার প্রয়োজন না হয়:
array=(a c b f 3 5)
sorted=($(printf '%s\n' "${array[@]}"|sort))
সঙ্গে ব্যাশ যাইহোক আপনি একটি বহিস্থিত বাছাই প্রোগ্রাম দরকার হবে।
সঙ্গে zsh কোন বহিরাগত প্রোগ্রাম প্রয়োজন হয় এবং বিশেষ শেল অক্ষর সহজে পরিচালনা করা হয়:
% array=('a a' c b f 3 5); printf '%s\n' "${(o)array[@]}"
3
5
a a
b
c
f
ksh হয়েছে set -s
সাজাতে ASCIIbetically ।
set -A array x 'a a' d; set -s -- "${array[@]}"; set -A sorted "$@"
এবং অবশ্যই, সেট কমান্ড বর্তমান অবস্থানগত পরামিতিগুলিকে পুনরায় সেট করবে, যদি কোনও হয়।
tl; dr :
অ্যারে বাছাই করুন a_in
এবং ফলাফল সংরক্ষণ করুন a_out
(উপাদানগুলি অবশ্যই নতুন লাইনে এম্বেড করা উচিত নয় [1]
):
বাশ ভি 4 +:
readarray -t a_out < <(printf '%s\n' "${a_in[@]}" | sort)
ভিশ ভি 3:
IFS=$'\n' read -d '' -r -a a_out < <(printf '%s\n' "${a_in[@]}" | sort)
এন্টাকের সমাধানের জন্য উপকারিতা :
আপনাকে দুর্ঘটনাজনিত গ্লোব্বিং (ফাইলের নামের ধরণ হিসাবে অ্যারের উপাদানগুলির আকস্মিক ব্যাখ্যা) সম্পর্কে চিন্তা করার দরকার নেই, সুতরাং গ্লোব্বিং নিষ্ক্রিয় করতে ( set -f
এবং set +f
পরে এটি পুনরুদ্ধার করার জন্য) কোনও অতিরিক্ত কমান্ডের প্রয়োজন নেই ।
আপনার IFS
সাথে পুনরায় সেট করার বিষয়ে চিন্তা করার দরকার নেই unset IFS
। [2]
বহিরাগত ইউটিলিটি সাথে উপরে সম্মিলন ব্যাশ কোড sort
একটি সমাধান যে অবাধ সাথে কাজে একক লাইন উপাদান এবং হয় আভিধানিক অথবা সংখ্যাসূচক শ্রেণীবিভাজন (ঐচ্ছিকভাবে ক্ষেত্র দ্বারা) :
পারফরম্যান্স : প্রায় 20 টি ততোধিক উপাদানগুলির জন্য এটি খাঁটি বাশ সমাধানের চেয়ে দ্রুত হবে - উল্লেখযোগ্যভাবে এবং ক্রমবর্ধমান তাই একবার আপনি প্রায় 100 টি উপাদান ছাড়িয়ে গেলে।
(সঠিক চৌম্বকটি আপনার নির্দিষ্ট ইনপুট, মেশিন এবং প্ল্যাটফর্মের উপর নির্ভর করবে))
printf '%s\n' "${a_in[@]}" | sort
বাছাই সঞ্চালন করে (ডিক্সডিক্যালি, ডিফল্ট অনুসারে - sort
এর পসিক্স স্পেস দেখুন ):
"${a_in[@]}"
সুরক্ষার সাথে অ্যারের উপাদানগুলিতে স্বতন্ত্র আর্গুমেন্টa_in
হিসাবে প্রসারিত হয় , এতে যা কিছু থাকে (হোয়াইটস্পেস সহ)।
printf '%s\n'
তারপরে প্রতিটি আর্গুমেন্ট - যেমন প্রতিটি অ্যারে উপাদান - তার নিজস্ব লাইনে মুদ্রণ করে।
উল্লেখ্য একটি ব্যবহার (প্রক্রিয়া প্রতিকল্পন <(...)
) ইনপুট হিসাবে সাজানো আউটপুট প্রদান read
/ readarray
(stdin, এর ফেরৎ মাধ্যমে <
,) কারণ read
/ readarray
চালানোর আবশ্যক বর্তমান শেল (ক চালানোর না subshell আউটপুট পরিবর্তনশীল জন্য) যাতে a_out
দৃশ্যমান হতে বর্তমান শেলটিতে (স্ক্রিপ্টের অবশিষ্ট অংশে পরিবর্তনশীল হিসাবে সংজ্ঞায়িত হওয়ার জন্য)।
sort
একটি অ্যারে ভেরিয়েবলের আউটপুট পড়া :
বাশ ভি 4 +: প্রতিটি উপাদান ( ) এর পিছনে অন্তর্ভুক্ত না করে অ্যারে ভেরিয়েবলের উপাদানগুলিতে readarray -t a_out
পৃথক লাইন আউটপুট sort
পড়বে ।a_out
\n
-t
বাশ ভি 3: readarray
বিদ্যমান নেই, তাই read
অবশ্যই ব্যবহার করতে হবে: অ্যারে ( ) পরিবর্তনশীলে পড়তে
IFS=$'\n' read -d '' -r -a a_out
বলে , পুরো ইনপুটটি লাইন জুড়ে read
( -a
) পড়তে বলে , তবে এটিকে অ্যারের উপাদানগুলিতে নিউলাইন দ্বারা বিভক্ত করে ( । , যা একটি আক্ষরিক নিউলাইন তৈরি করে (এলএফ ), এটি একটি তথাকথিত এএনএসআই সি-উদ্ধৃত স্ট্রিং )।
( , এমন একটি বিকল্প যা কার্যত সর্বদা ব্যবহার করা উচিত , অক্ষরগুলির অপ্রত্যাশিত পরিচালনা পরিচালনা অক্ষম করে ))a_out
-d ''
IFS=$'\n'
$'\n'
-r
read
\
স্বীকৃত নমুনা কোড:
#!/usr/bin/env bash
# Define input array `a_in`:
# Note the element with embedded whitespace ('a c')and the element that looks like
# a glob ('*'), chosen to demonstrate that elements with line-internal whitespace
# and glob-like contents are correctly preserved.
a_in=( 'a c' b f 5 '*' 10 )
# Sort and store output in array `a_out`
# Saving back into `a_in` is also an option.
IFS=$'\n' read -d '' -r -a a_out < <(printf '%s\n' "${a_in[@]}" | sort)
# Bash 4.x: use the simpler `readarray -t`:
# readarray -t a_out < <(printf '%s\n' "${a_in[@]}" | sort)
# Print sorted output array, line by line:
printf '%s\n' "${a_out[@]}"
sort
বিকল্প ছাড়াই ব্যবহারের কারণে , এইটি লেজিকাল বাছাই করে (অক্ষরের আগে অঙ্কগুলি এবং অঙ্কের ক্রমগুলি সংখ্যার হিসাবে নয়) লাক্ষিকভাবে চিকিত্সা করা হয়:
*
10
5
a c
b
f
যদি আপনি 1 ম ক্ষেত্রের মাধ্যমে সংখ্যা বাছাই করতে চান, আপনি ন্যায়বিচারের sort -k1,1n
পরিবর্তে ব্যবহার করবেন sort
, যা ফল দেয় (সংখ্যার আগে অ-সংখ্যাগুলি বাছাই করুন এবং সংখ্যাগুলি সঠিকভাবে সাজান):
*
a c
b
f
5
10
[1] এমবেডেড নতুন লাইন দিয়ে হ্যান্ডেল উপাদান, নিম্নলিখিত বৈকল্পিক (ব্যাশ V4 + এর সাথে ব্যবহার গনুহ sort
):
readarray -d '' -t a_out < <(printf '%s\0' "${a_in[@]}" | sort -z)
।
মিশা গার্নির সহায়ক উত্তরের একটি বাশ ভি 3 সমাধান রয়েছে।
[2] যদিও IFS
হয় ব্যাশ v3 এর বৈকল্পিক মধ্যে সেট, পরিবর্তন করা হয় কমান্ড scoped ।
বিপরীতে, IFS=$'\n'
এন্টাকের উত্তরে যা অনুসরণ করা হয় তা হ'ল আদেশের পরিবর্তে একটি কার্যনির্বাহ , সেই ক্ষেত্রে IFS
পরিবর্তনটি বিশ্বব্যাপী ।
মিউনিখ থেকে ফ্রাঙ্কফুর্টে 3 ঘন্টা ট্রেনের ভ্রমণের (যা পৌঁছাতে আমার অসুবিধা হয়েছিল কারণ ওক্টোবারফেষ্ট আগামীকাল শুরু হয়) আমি আমার প্রথম পোস্টটি নিয়ে ভাবছিলাম। গ্লোবাল অ্যারে নিয়োগ করা একটি সাধারণ সাজানোর ক্রিয়াকলাপের জন্য আরও ভাল ধারণা। নিম্নলিখিত ফাংশন সালিসি স্ট্রিংগুলি পরিচালনা করে (নিউলাইনস, ফাঁকা ইত্যাদি):
declare BSORT=()
function bubble_sort()
{ #
# @param [ARGUMENTS]...
#
# Sort all positional arguments and store them in global array BSORT.
# Without arguments sort this array. Return the number of iterations made.
#
# Bubble sorting lets the heaviest element sink to the bottom.
#
(($# > 0)) && BSORT=("$@")
local j=0 ubound=$((${#BSORT[*]} - 1))
while ((ubound > 0))
do
local i=0
while ((i < ubound))
do
if [ "${BSORT[$i]}" \> "${BSORT[$((i + 1))]}" ]
then
local t="${BSORT[$i]}"
BSORT[$i]="${BSORT[$((i + 1))]}"
BSORT[$((i + 1))]="$t"
fi
((++i))
done
((++j))
((--ubound))
done
echo $j
}
bubble_sort a c b 'z y' 3 5
echo ${BSORT[@]}
এই মুদ্রণ:
3 5 a b c z y
একই আউটপুট থেকে তৈরি করা হয়
BSORT=(a c b 'z y' 3 5)
bubble_sort
echo ${BSORT[@]}
নোট করুন যে সম্ভবত বাশ অভ্যন্তরীণভাবে স্মার্ট পয়েন্টার ব্যবহার করে, তাই সোয়াপ-অপারেশনটি সস্তা হতে পারে (যদিও আমি এটি সন্দেহ করি)। তবে, bubble_sort
দেখায় যে আরও উন্নত ফাংশনগুলিও merge_sort
শেল ভাষার নাগালের মধ্যে রয়েছে।
local -n BSORT="$1"
ফাংশনের শুরুতে। তারপরে আপনি ম্যারিরেbubble_sort myarray
বাছাই করতে ছুটে যেতে পারেন ।
আর একটি সমাধান যা বাহ্যিক ব্যবহার করে sort
এবং কোনও বিশেষ অক্ষরের সাথে অনুলিপি করে (NULs :) ব্যতীত)। বাশ -৩.২ এবং জিএনইউ বা বিএসডি নিয়ে কাজ করা উচিত sort
(দুঃখের বিষয়, পসিক্স অন্তর্ভুক্ত নয় -z
)।
local e new_array=()
while IFS= read -r -d '' e; do
new_array+=( "${e}" )
done < <(printf "%s\0" "${array[@]}" | LC_ALL=C sort -z)
প্রথমে শেষে ইনপুট পুনর্নির্দেশটি দেখুন। আমরা printf
শূন্য-সমাপ্ত অ্যারে উপাদানগুলি লিখতে অন্তর্নির্মিত ব্যবহার করছি । উদ্ধৃতিটি নিশ্চিত করে যে অ্যারে উপাদানগুলি যেমন রয়েছে তেমন পাস হয়েছে এবং শেলের নির্দিষ্টকরণের printf
ফলে এটি প্রতিটি অবশিষ্ট প্যারামিটারের জন্য বিন্যাসের স্ট্রিংয়ের শেষ অংশটি পুনরায় ব্যবহার করতে পারে। এটি এর মতো কিছু সমতুল্য:
for e in "${array[@]}"; do
printf "%s\0" "${e}"
done
নাল-টার্মিনেটেড এলিমেন্ট লিস্টটি এর পরে দেওয়া হয় sort
। -z
বিকল্প নাল-সমাপ্ত উপাদান, সাজানোর তাদের এবং আউটপুট পাশাপাশি নাল-সমাপ্ত পড়তে এটা ঘটায়। আপনার যদি কেবল অনন্য উপাদানগুলির প্রয়োজন হয় তবে আপনি -u
এটির চেয়ে বেশি বহনযোগ্য হিসাবে পাস করতে পারেন uniq -z
। স্থানীয়ভাবে LC_ALL=C
স্থিতিশীল সাজানোর অর্ডার নিশ্চিত করে - কখনও কখনও স্ক্রিপ্টগুলির জন্য দরকারী। আপনি যদি sort
লোকেলের প্রতি শ্রদ্ধা জানাতে চান তবে তা সরিয়ে দিন।
<()
কনস্ট্রাক্ট বর্ণনাকারী সংগ্রহ উত্পন্ন হওয়া পাইপলাইন থেকে পড়তে এবং <
মান ইনপুট পুননির্দেশনা while
এটি লুপ। পাইপের অভ্যন্তরে যদি আপনার স্ট্যান্ডার্ড ইনপুটটি অ্যাক্সেস করার প্রয়োজন হয় তবে আপনি অন্য বর্ণনাকারী ব্যবহার করতে পারেন - পাঠকের জন্য অনুশীলন :)।
এখন, আবার শুরুতে। read
বিল্ট-ইন REDIRECTED stdin থেকে আউটপুট পড়ে। খালি সেট করা IFS
শব্দ বিভাজনকে অক্ষম করে যা এখানে অপ্রয়োজনীয় - ফলস্বরূপ, read
একক সরবরাহিত ভেরিয়েবলের ইনপুটটির পুরো 'লাইন' পড়ে। -r
বিকল্পটি এখানেও অনাকাঙ্ক্ষিত পলায়ন প্রক্রিয়াটিকে অক্ষম করে। অবশেষে, -d ''
রেখার ডিলিমিটারটি NUL এ সেট করে - এটি read
শূন্য-সমাপ্ত স্ট্রিংগুলি পড়তে বলে ।
ফলস্বরূপ, লুপটি প্রতিটি ক্রমাগত শূন্য-সমাপ্ত অ্যারে উপাদানটির জন্য একবারে কার্যকর করা হয়, মানটি সঞ্চিত থাকে e
। উদাহরণটি কেবল আইটেমগুলিকে অন্য অ্যারে রাখে তবে আপনি সেগুলি সরাসরি প্রক্রিয়া করতে পছন্দ করতে পারেন :)।
অবশ্যই, এটি একই লক্ষ্য অর্জনের বিভিন্ন উপায়গুলির মধ্যে একটি। আমি এটি দেখতে পাচ্ছি, ব্যাশে সম্পূর্ণ বাছাই করা অ্যালগরিদম বাস্তবায়নের চেয়ে সহজ এবং কিছু ক্ষেত্রে এটি আরও দ্রুত হবে। এটি নিউলাইনগুলি সহ সমস্ত বিশেষ অক্ষর পরিচালনা করে এবং বেশিরভাগ সাধারণ সিস্টেমে কাজ করা উচিত। সর্বাধিক গুরুত্বপূর্ণ, এটি আপনাকে বাশ সম্পর্কে নতুন এবং দুর্দান্ত কিছু শেখাতে পারে :)।
e
এবং খালি আইএফএস স্থাপনের পরিবর্তে, রিপ্লে ভেরিয়েবলটি ব্যবহার করুন।
এটা চেষ্টা কর:
echo ${array[@]} | awk 'BEGIN{RS=" ";} {print $1}' | sort
আউটপুট হবে:
3 5 একটি খ গ চ
সমস্যা সমাধান.
আপনি যদি অ্যারের প্রতিটি উপাদানের জন্য একটি অনন্য পূর্ণসংখ্যা গণনা করতে পারেন তবে:
tab='0123456789abcdefghijklmnopqrstuvwxyz'
# build the reversed ordinal map
for ((i = 0; i < ${#tab}; i++)); do
declare -g ord_${tab:i:1}=$i
done
function sexy_int() {
local sum=0
local i ch ref
for ((i = 0; i < ${#1}; i++)); do
ch="${1:i:1}"
ref="ord_$ch"
(( sum += ${!ref} ))
done
return $sum
}
sexy_int hello
echo "hello -> $?"
sexy_int world
echo "world -> $?"
তারপরে, আপনি এই সংখ্যাগুলি অ্যারে সূচক হিসাবে ব্যবহার করতে পারেন, কারণ বাশ সর্বদা বিরল অ্যারে ব্যবহার করে, তাই অব্যবহৃত সূচকগুলি নিয়ে চিন্তা করার দরকার নেই:
array=(a c b f 3 5)
for el in "${array[@]}"; do
sexy_int "$el"
sorted[$?]="$el"
done
echo "${sorted[@]}"
নূন্যতম সাজান:
#!/bin/bash
array=(.....)
index_of_element1=0
while (( ${index_of_element1} < ${#array[@]} )); do
element_1="${array[${index_of_element1}]}"
index_of_element2=$((index_of_element1 + 1))
index_of_min=${index_of_element1}
min_element="${element_1}"
for element_2 in "${array[@]:$((index_of_element1 + 1))}"; do
min_element="`printf "%s\n%s" "${min_element}" "${element_2}" | sort | head -n+1`"
if [[ "${min_element}" == "${element_2}" ]]; then
index_of_min=${index_of_element2}
fi
let index_of_element2++
done
array[${index_of_element1}]="${min_element}"
array[${index_of_min}]="${element_1}"
let index_of_element1++
done
স্পেস এবং নিউলাইনগুলির স্বাভাবিক সমস্যার জন্য একটি সমাধান রয়েছে:
এমন অক্ষর ব্যবহার করুন যা মূল অ্যারেতে নেই (যেমন $'\1'
বা$'\4'
বা অনুরূপ)।
এই ফাংশনটি কাজটি সম্পন্ন করে:
# Sort an Array may have spaces or newlines with a workaround (wa=$'\4')
sortarray(){ local wa=$'\4' IFS=''
if [[ $* =~ [$wa] ]]; then
echo "$0: error: array contains the workaround char" >&2
exit 1
fi
set -f; local IFS=$'\n' x nl=$'\n'
set -- $(printf '%s\n' "${@//$nl/$wa}" | sort -n)
for x
do sorted+=("${x//$wa/$nl}")
done
}
এটি অ্যারে বাছাই করবে:
$ array=( a b 'c d' $'e\nf' $'g\1h')
$ sortarray "${array[@]}"
$ printf '<%s>\n' "${sorted[@]}"
<a>
<b>
<c d>
<e
f>
<gh>
এটি অভিযোগ করবে যে উত্স অ্যারেটিতে কার্যক্ষম চরিত্রটি রয়েছে:
$ array=( a b 'c d' $'e\nf' $'g\4h')
$ sortarray "${array[@]}"
./script: error: array contains the workaround char
wa
(ওয়ার্কআরউন্ড চর) এবং একটি নাল আইএফএস সেট করি$*
।[[ $* =~ [$wa] ]]
।exit 1
set -f
IFS=$'\n'
) একটি লুপ ভেরিয়েবল x
এবং একটি নতুন লাইন ভার ( nl=$'\n'
) নির্ধারণ করুন।$@
)।"${@//$nl/$wa}"
।sort -n
।set --
।for x
sorted+=(…)
"${x//$wa/$nl}"
।এই প্রশ্নটি নিবিড়ভাবে সম্পর্কিত বলে মনে হচ্ছে। এবং বিটিডাব্লু, এখানে বাশের একত্রীকরণ (বাহ্যিক প্রক্রিয়া ব্যতীত):
mergesort() {
local -n -r input_reference="$1"
local -n output_reference="$2"
local -r -i size="${#input_reference[@]}"
local merge previous
local -a -i runs indices
local -i index previous_idx merged_idx \
run_a_idx run_a_stop \
run_b_idx run_b_stop
output_reference=("${input_reference[@]}")
if ((size == 0)); then return; fi
previous="${output_reference[0]}"
runs=(0)
for ((index = 0;;)) do
for ((++index;; ++index)); do
if ((index >= size)); then break 2; fi
if [[ "${output_reference[index]}" < "$previous" ]]; then break; fi
previous="${output_reference[index]}"
done
previous="${output_reference[index]}"
runs+=(index)
done
runs+=(size)
while (("${#runs[@]}" > 2)); do
indices=("${!runs[@]}")
merge=("${output_reference[@]}")
for ((index = 0; index < "${#indices[@]}" - 2; index += 2)); do
merged_idx=runs[indices[index]]
run_a_idx=merged_idx
previous_idx=indices[$((index + 1))]
run_a_stop=runs[previous_idx]
run_b_idx=runs[previous_idx]
run_b_stop=runs[indices[$((index + 2))]]
unset runs[previous_idx]
while ((run_a_idx < run_a_stop && run_b_idx < run_b_stop)); do
if [[ "${merge[run_a_idx]}" < "${merge[run_b_idx]}" ]]; then
output_reference[merged_idx++]="${merge[run_a_idx++]}"
else
output_reference[merged_idx++]="${merge[run_b_idx++]}"
fi
done
while ((run_a_idx < run_a_stop)); do
output_reference[merged_idx++]="${merge[run_a_idx++]}"
done
while ((run_b_idx < run_b_stop)); do
output_reference[merged_idx++]="${merge[run_b_idx++]}"
done
done
done
}
declare -ar input=({z..a}{z..a})
declare -a output
mergesort input output
echo "${input[@]}"
echo "${output[@]}"
আমি নিশ্চিত নই যে আপনার বাশে একটি বাহ্যিক বাছাই প্রোগ্রাম প্রয়োজন।
সাধারণ বুদ্বুদ-সাজানোর অ্যালগরিদমের জন্য আমার বাস্তবায়ন এখানে।
function bubble_sort()
{ #
# Sorts all positional arguments and echoes them back.
#
# Bubble sorting lets the heaviest (longest) element sink to the bottom.
#
local array=($@) max=$(($# - 1))
while ((max > 0))
do
local i=0
while ((i < max))
do
if [ ${array[$i]} \> ${array[$((i + 1))]} ]
then
local t=${array[$i]}
array[$i]=${array[$((i + 1))]}
array[$((i + 1))]=$t
fi
((i += 1))
done
((max -= 1))
done
echo ${array[@]}
}
array=(a c b f 3 5)
echo " input: ${array[@]}"
echo "output: $(bubble_sort ${array[@]})"
এটি মুদ্রণ করতে হবে:
input: a c b f 3 5
output: 3 5 a b c f
O(n^2)
। আমি মনে করি বেশিরভাগ বাছাই করা অ্যালগরিদমগুলি O(n lg(n))
চূড়ান্ত ডজন উপাদান বা ততক্ষণ পর্যন্ত ব্যবহার করে। চূড়ান্ত উপাদানগুলির জন্য, নির্বাচনের বাছাই ব্যবহৃত হয়।
a=(e b 'c d')
shuf -e "${a[@]}" | sort >/tmp/f
mapfile -t g </tmp/f
sorted=($(echo ${array[@]} | tr " " "\n" | sort))
বাশ / লিনাক্সের চেতনায় আমি প্রতিটি পদক্ষেপের জন্য সেরা কমান্ড-লাইন সরঞ্জামটি পাইপ করব। sort
মূল কাজটি করে তবে স্থানের পরিবর্তে নিউলাইন দ্বারা পৃথক ইনপুট প্রয়োজন, সুতরাং উপরের খুব সাধারণ পাইপলাইনটি কেবল এটি করে:
ইকো অ্যারের সামগ্রী -> স্থানটি নতুন লাইনের মাধ্যমে প্রতিস্থাপন করুন -> সাজান
$()
ফলাফল প্রতিধ্বনিত হয়
($())
একটি অ্যারেতে "প্রতিধ্বনিত ফলাফল" স্থাপন করা
দ্রষ্টব্য : @ সোরন্টার যেমন একটি পৃথক প্রশ্নের মন্তব্যে উল্লেখ করেছেন :
সাজানো = ($ (...)) অংশটি "বিভক্ত এবং গ্লোব" অপারেটরটি ব্যবহার করছে। আপনার গ্লোব বন্ধ করা উচিত: সেট -f বা সেট-ও নোগ্লোব বা শপট -প নোগ্লোব বা অ্যারের উপাদান যেমন * ফাইলের তালিকায় প্রসারিত হবে।
mapfile -t sorted < <(printf '%s\n' "${array[@]}" | sort)
অন্যথায় sorted=(); while IFS= read -r line; do sorted+=( "$line" ); done < <(printf '%s\n' | sort)
।
echo ${array[@]} | tr " " "\n"
: অ্যারের ক্ষেত্রগুলিতে হোয়াইটস্পেস এবং গ্লোব অক্ষর থাকলে এটি ভেঙে যাবে। তদ্ব্যতীত, এটি একটি সাবশেল তৈরি করে এবং অকেজো বাইরের কমান্ড ব্যবহার করে। এবং echo
বোবা হওয়ার কারণে , যদি আপনার অ্যারে শুরু হয় -e
, -E
বা এটি ভেঙে যাবে -n
। এর পরিবর্তে ব্যবহার করুন: printf '%s\n' "${array[@]}"
। অন্যান্য অ্যান্টিপ্যাটার্ন হ'ল: ($())
"প্রতিধ্বনিত ফলাফল" একটি অ্যারেতে রাখা । অবশ্যই না! এটি একটি ভয়ঙ্কর অ্যান্টিপ্যাটার্ন যা পাথের নাম সম্প্রসারণ (গ্লোব্বিং) এবং শব্দ বিভাজনের কারণে ভেঙে যায়। এই ভয়াবহতা কখনই ব্যবহার করবেন না।
IFS
, যদি আপনার শ্বেত স্পেস থাকে তবে এটি আপনার উপাদানগুলিকে সামান্য টুকরো টুকরো করবে। যেমনIFS=$'\n'
বাদ দিয়ে দেখুন চেষ্টা করুন !