Немного взломано, но это должно сработать:
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
Чтобы сохранить отсортированные уникальные результаты обратно в массив, выполните Array assignment :
sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
Если ваша оболочка поддерживает herestrings ( 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 ожидает ввода в отдельные строки.
sort -u
- сортировать и сохранять только уникальные элементы
tr '\n' ' '
- преобразовать символы новой строки, которые мы добавили ранее, обратно в пробелы.
$(...)
- Подмена команд
- Кроме того:
tr ' ' '\n' <<< "${ids[@]}"
это более эффективный способ:echo "${ids[@]}" | tr ' ' '\n'
uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"
printf
этот способ (приводите больше аргументов, чем строки формата)sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
. Без дополнительных скобок он давал это как строку.... | uniq | ...
вместо... | sort -u | ...
.uniq
удаляет только последовательные дубликаты. В примере в этом ответеsorted_unique_ids
будет идентично оригиналуids
. Чтобы сохранить порядок, попробуйте... | awk '!seen[$0]++'
. См. Также stackoverflow.com/questions/1444406/… .Если вы используете 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
ina[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.источник
Я понимаю, что на этот вопрос уже был дан ответ, но он оказался довольно высоко в результатах поиска и может кому-то помочь.
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 ~>
источник
ids=(ab "a a" ac aa ad ac aa);IFS=$'\n' ids2=(`printf "%s\n" "${ids[@]}" |sort -u`)
поэтому я добавил,IFS=$'\n'
предложенный @gniourf_gniourfIFS=$'\n'; ids2=(...)
поскольку временное присвоение перед назначением переменных невозможно. Вместо того, чтобы использовать эту конструкцию:IFS=$'\n' read -r -a ids2 <<<"$(printf "%s\n" "${ids[@]}" | sort -u)"
.Если в ваших элементах массива есть пробел или какой-либо другой специальный символ оболочки (и можете ли вы быть уверены, что они отсутствуют?), То, чтобы захватить их в первую очередь (и вы всегда должны делать это), выразите свой массив в двойных кавычках! напр
"${a[@]}"
. Bash буквально интерпретирует это как «каждый элемент массива в отдельном аргументе ». В bash это всегда работает, всегда.Затем, чтобы получить отсортированный (и уникальный) массив, мы должны преобразовать его в формат, понятный для сортировки, и иметь возможность преобразовать его обратно в элементы массива bash. Это лучшее, что я придумал:
eval a=($(printf "%q\n" "${a[@]}" | sort -u))
К сожалению, это не удается в частном случае пустого массива, превращая пустой массив в массив из 1 пустого элемента (потому что printf имеет 0 аргументов, но все равно печатает, как если бы он имел один пустой аргумент - см. Объяснение). Так что вы должны уловить это в if или чем-то подобном.
Объяснение: Формат% q для printf "экранирует оболочку" напечатанного аргумента, точно так же, как bash может восстановить что-то вроде eval! Поскольку каждый элемент печатается оболочкой с экранированием на собственной строке, единственным разделителем между элементами является новая строка, а присвоение массива принимает каждую строку как элемент, анализируя экранированные значения в буквальный текст.
например
> a=("foo bar" baz) > printf "%q\n" "${a[@]}" 'foo bar' baz > printf "%q\n" ''
Eval необходим для удаления экранирования каждого значения, возвращаемого в массив.
источник
uniq
вместоsort -u
.uniq
это не работает должным образом с несортированными списками, поэтому его всегда следует использовать в сочетании сsort
.'sort' может использоваться для упорядочивания вывода цикла for:
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` )
этот тоже сохранит порядок:
echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'
и изменить исходный массив уникальными значениями:
ARRAY=($(echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'))
источник
uniq
. Ему нужна сортировка, в отличие от awk, и цель этого ответа - сохранить порядок, когда ввод не отсортирован.Чтобы создать новый массив, состоящий из уникальных значений, убедитесь, что ваш массив не пуст, а затем выполните одно из следующих действий:
Удалить повторяющиеся записи (с сортировкой)
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]++'
.источник
Без потери первоначального заказа:
uniques=($(tr ' ' '\n' <<<"${original[@]}" | awk '!u[$0]++' | tr '\n' ' '))
источник
Если вам нужно решение, которое использует только внутренние компоненты bash, вы можете установить значения как ключи в ассоциативном массиве, а затем извлечь ключи:
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
Это выведет
источник
Другой вариант работы со встроенными пробелами - разделить нуль с помощью
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'
источник
Как насчет этого варианта?
printf '%s\n' "${ids[@]}" | sort -u
источник
sorted_arr=($(printf '%s\n' "${ids[@]}" | sort -u)
.Попробуйте это, чтобы получить значения uniq для первого столбца в файле
awk -F, '{a[$1];}END{for (i in a)print i;}'
источник
# 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
источник