Trochę hacky, ale to powinno wystarczyć:
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
Aby zapisać posortowane unikalne wyniki z powrotem w tablicy, wykonaj przypisanie tablicy :
sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
Jeśli twoja powłoka obsługuje ciągi tutaj ( bash
powinno), możesz oszczędzić echo
proces, zmieniając go na:
tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '
Wejście:
ids=(aa ab aa ac aa ad)
Wynik:
aa ab ac ad
Wyjaśnienie:
"${ids[@]}"
- Składnia do pracy z tablicami powłoki, używana jako część echo
lub ciąg znaków. W @
części „oznacza wszystkie pozycje w tablicy”
tr ' ' '\n'
- Konwertuj wszystkie spacje na znaki nowej linii. Ponieważ twoja tablica jest widziana przez powłokę jako elementy w jednym wierszu, oddzielone spacjami; a ponieważ sort oczekuje, że wejście będzie w oddzielnych wierszach.
sort -u
- sortuj i zachowuj tylko unikalne elementy
tr '\n' ' '
- przekonwertuj nowe linie, które dodaliśmy wcześniej z powrotem do spacji.
$(...)
- Zastępowanie poleceń
- Poza tym:
tr ' ' '\n' <<< "${ids[@]}"
to bardziej efektywny sposób:echo "${ids[@]}" | tr ' ' '\n'
uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"
printf
w ten sposób (podać więcej argumentów niż ciągi format)sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
. Bez dodatkowych nawiasów podawał jako ciąg.... | uniq | ...
zamiast... | sort -u | ...
.uniq
usuwa tylko kolejne duplikaty. W przykładzie w tej odpowiedzisorted_unique_ids
skończy się identycznie jak oryginałids
. Aby zachować porządek, spróbuj... | awk '!seen[$0]++'
. Zobacz także stackoverflow.com/questions/1444406/… .Jeśli używasz Bash w wersji 4 lub nowszej (co powinno mieć miejsce w każdej nowoczesnej wersji Linuksa), możesz uzyskać unikalne wartości tablic w bash, tworząc nową tablicę asocjacyjną zawierającą każdą z wartości oryginalnej tablicy. Coś takiego:
$ 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
To działa, ponieważ w dowolnej tablicy (asocjacyjnej lub tradycyjnej, w dowolnym języku) każdy klucz może wystąpić tylko raz. Kiedy
for
pętla osiąga drugą wartośćaa
ina[2]
, nadpisujeb[aa]
pierwotnie ustawioną wartośća[0]
.Robienie rzeczy w natywnym bashu może być szybsze niż używanie potoków i zewnętrznych narzędzi, takich jak
sort
iuniq
, chociaż w przypadku większych zestawów danych prawdopodobnie zobaczysz lepszą wydajność, jeśli użyjesz mocniejszego języka, takiego jak awk, python itp.Jeśli czujesz się pewnie, możesz uniknąć
for
pętli, korzystającprintf
z możliwości ponownego wykorzystania formatu dla wielu argumentów, chociaż wydaje się to wymagaćeval
. (Przestań czytać teraz, jeśli nie masz nic przeciwko.)$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") ) $ declare -p b declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )
Powodem, dla którego to rozwiązanie wymaga,
eval
jest to, że wartości tablic są określane przed podziałem na słowa. Oznacza to, że wynik podstawienia polecenia jest traktowany jako pojedyncze słowo a nie zestaw par klucz = wartość.Chociaż używa podpowłoki, używa tylko wbudowanych bash do przetwarzania wartości tablic. Pamiętaj, aby
eval
krytycznym okiem ocenić swoje użycie . Jeśli nie masz 100% pewności, że chepner, glenn jackman lub greycat nie znajdzie żadnych błędów w twoim kodzie, użyj zamiast tego pętli for.źródło
Zdaję sobie sprawę, że odpowiedź na to pytanie została już udzielona, ale pojawiło się dość wysoko w wynikach wyszukiwania i może komuś pomóc.
printf "%s\n" "${IDS[@]}" | sort -u
Przykład:
~> 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 ~>
źródło
ids=(ab "a a" ac aa ad ac aa);IFS=$'\n' ids2=(`printf "%s\n" "${ids[@]}" |sort -u`)
więc dodałemIFS=$'\n'
sugerowane przez @gniourf_gniourfIFS=$'\n'; ids2=(...)
ponieważ tymczasowe przypisanie przed przypisaniem zmiennych nie jest możliwe. Zamiast korzystać z tej konstrukcji:IFS=$'\n' read -r -a ids2 <<<"$(printf "%s\n" "${ids[@]}" | sort -u)"
.Jeśli elementy tablicy mają białe spacje lub jakikolwiek inny znak specjalny powłoki (i czy możesz być pewien, że tak nie jest?), To aby je najpierw uchwycić (i zawsze powinieneś to robić), wyrażaj tablicę w podwójnych cudzysłowach! np
"${a[@]}"
. Bash dosłownie zinterpretuje to jako „każdy element tablicy w osobnym argumencie” ”. W bashu to po prostu zawsze działa, zawsze.Następnie, aby uzyskać posortowaną (i unikalną) tablicę, musimy przekonwertować ją na format, który rozumie sortowanie i być w stanie przekonwertować ją z powrotem na elementy tablicy bash. Oto najlepsze, co wymyśliłem:
eval a=($(printf "%q\n" "${a[@]}" | sort -u))
Niestety, kończy się to niepowodzeniem w specjalnym przypadku pustej tablicy, przekształcając pustą tablicę w tablicę zawierającą 1 pusty element (ponieważ printf miał 0 argumentów, ale nadal drukuje tak, jakby miał jeden pusty argument - patrz wyjaśnienie). Więc musisz to złapać w „jeśli” lub czymś.
Objaśnienie: Format% q dla printf "powłoki ucieka" z wypisanego argumentu, w taki sposób, że bash może odzyskać w czymś takim jak eval! Ponieważ każdy element jest wypisywany w powłoce ze znakami ucieczki w swoim własnym wierszu, jedynym separatorem między elementami jest znak nowej linii, a przypisanie tablicy przyjmuje każdy wiersz jako element, przetwarzając wartości ucieczki na tekst literału.
na przykład
> a=("foo bar" baz) > printf "%q\n" "${a[@]}" 'foo bar' baz > printf "%q\n" ''
Wartość eval jest konieczna, aby usunąć ucieczkę z każdej wartości wracającej do tablicy.
źródło
uniq
zamiastsort -u
.uniq
nie działa poprawnie w przypadku niesortowanych list, dlatego należy go zawsze używać w połączeniu zsort
.'sort' może być użyte do uporządkowania wyników pętli for:
for i in ${ids[@]}; do echo $i; done | sort
i usuń duplikaty za pomocą „-u”:
for i in ${ids[@]}; do echo $i; done | sort -u
Wreszcie możesz po prostu nadpisać swoją tablicę unikalnymi elementami:
ids=( `for i in ${ids[@]}; do echo $i; done | sort -u` )
źródło
ids=( `for i in ${ids[@]}; do echo $i; done | uniq` )
ten też zachowa porządek:
echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'
i zmodyfikować oryginalną tablicę z unikalnymi wartościami:
ARRAY=($(echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'))
źródło
uniq
. Wymaga sortowania, gdy awk tego nie robi, a celem tej odpowiedzi jest zachowanie kolejności, gdy dane wejściowe nie są posortowane.Aby utworzyć nową tablicę składającą się z unikalnych wartości, upewnij się, że tablica nie jest pusta, a następnie wykonaj jedną z następujących czynności:
Usuń zduplikowane wpisy (z sortowaniem)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | sort -u)
Usuń zduplikowane wpisy (bez sortowania)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | awk '!x[$0]++')
Ostrzeżenie: nie próbuj robić czegoś takiego
NewArray=( $(printf '%s\n' "${OriginalArray[@]}" | sort -u) )
. Będzie pękać na przestrzeniach.źródło
sort -u
która ma byćuniq
.uniq
scala tylko zduplikowane linie, które sąsiadują, więc nie jest tym samym, coawk '!x[$0]++'
.źródło
Bez utraty oryginalnego zamówienia:
uniques=($(tr ' ' '\n' <<<"${original[@]}" | awk '!u[$0]++' | tr '\n' ' '))
źródło
Jeśli potrzebujesz rozwiązania wykorzystującego tylko wewnętrzne funkcje bash, możesz ustawić wartości jako klucze w tablicy asocjacyjnej, a następnie wyodrębnić klucze:
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
To wyjdzie
źródło
Inną opcją radzenia sobie z osadzonymi białymi znakami jest oddzielenie go od wartości null
printf
, odróżnienie za pomocąsort
, a następnie użycie pętli do spakowania go z powrotem do tablicy: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)
Na końcu
input
ioutput
zawierają żądane wartości (pod warunkiem, że kolejność nie jest ważna):$ printf "%q\n" "${input[@]}" a b c $'d\ne' b c $'d\ne' $ printf "%q\n" "${output[@]}" a b c $'d\ne'
źródło
A co z tą odmianą?
printf '%s\n' "${ids[@]}" | sort -u
źródło
sorted_arr=($(printf '%s\n' "${ids[@]}" | sort -u)
.Spróbuj tego, aby uzyskać unikalne wartości dla pierwszej kolumny w pliku
awk -F, '{a[$1];}END{for (i in a)print i;}'
źródło
# 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
źródło