Якщо у вас запущена версія Bash 4 або вище (що має бути в будь-якій сучасній версії Linux), ви можете отримати унікальні значення масиву в bash, створивши новий асоціативний масив, що містить кожне зі значень вихідного масиву. Щось на зразок цього:
$ 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
Це працює, оскільки в будь-якому масиві (асоціативному чи традиційному, будь-якою мовою) кожна клавіша може відображатися лише один раз. Коли for
цикл отримує друге значення aa
in a[2]
, він перезаписує те, b[aa]
що було встановлено спочатку a[0]
.
Робити речі в рідній bash може бути швидше, ніж за допомогою конвеєрів та зовнішніх інструментів, таких як sort
і uniq
, хоча для більших наборів даних ви, швидше за все, побачите кращу продуктивність, якщо ви використовуєте більш потужну мову, таку як awk, python тощо.
Якщо ви впевнені в собі, ви можете уникнути 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
є те, що значення масиву визначаються перед розбиттям слів. Це означає, що результат заміни команди вважається одним словом, а не набором пар ключ = значення.
Незважаючи на те, що для цього використовується підшарка, вона використовує лише вбудовані bash для обробки значень масиву. Не забудьте оцінити своє вживання eval
критичним оком. Якщо ви не впевнені на 100%, що Чепнер або Глен Джекмен або сірий не знайдуть вади у вашому коді, використовуйте замість цього цикл for.
uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"