Якщо у вас запущена версія 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цикл отримує друге значення aain 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[@]}"