Если вы используете 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[@]}"