Agak hacky, tetapi ini harus dilakukan:
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
Untuk menyimpan hasil unik yang diurutkan kembali ke dalam array, lakukan penugasan Array :
sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
Jika shell Anda mendukung herestrings ( bash
harus), Anda dapat menghemat echo
proses dengan mengubahnya menjadi:
tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '
Memasukkan:
ids=(aa ab aa ac aa ad)
Keluaran:
aa ab ac ad
Penjelasan:
"${ids[@]}"
- Sintaks untuk bekerja dengan array shell, baik digunakan sebagai bagian dari echo
atau herestring. Bagian @
berarti "semua elemen dalam array"
tr ' ' '\n'
- Ubah semua spasi menjadi baris baru. Karena array Anda dilihat oleh shell sebagai elemen pada satu baris, dipisahkan oleh spasi; dan karena sort mengharapkan input berada di baris terpisah.
sort -u
- urutkan dan pertahankan hanya elemen unik
tr '\n' ' '
- ubah baris baru yang kami tambahkan sebelumnya kembali ke spasi.
$(...)
- Pergantian Perintah
- Selain:
tr ' ' '\n' <<< "${ids[@]}"
adalah cara yang lebih efisien untuk melakukan:echo "${ids[@]}" | tr ' ' '\n'
uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"
printf
cara itu (berikan lebih banyak argumen daripada format string)sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
. Tanpa tanda kurung tambahan, ini diberikan sebagai string.... | uniq | ...
bukan... | sort -u | ...
.uniq
hanya menghapus duplikat yang berurutan . Dalam contoh di jawaban ini,sorted_unique_ids
akan berakhir identik dengan aslinyaids
. Untuk menjaga ketertiban, cobalah... | awk '!seen[$0]++'
. Lihat juga stackoverflow.com/questions/1444406/… .Jika Anda menjalankan Bash versi 4 atau lebih tinggi (yang seharusnya terjadi pada versi Linux modern), Anda bisa mendapatkan nilai array unik di bash dengan membuat array asosiatif baru yang berisi setiap nilai dari array asli. Sesuatu seperti ini:
$ 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
Ini berfungsi karena dalam larik apa pun (asosiatif atau tradisional, dalam bahasa apa pun), setiap kunci hanya dapat muncul sekali. Ketika
for
perulangan tiba di nilai kedua dariaa
dalama[2]
, itu menimpab[aa]
yang awalnya ditetapkan untuka[0]
.Melakukan hal-hal di bash asli bisa lebih cepat daripada menggunakan pipa dan alat eksternal seperti
sort
danuniq
, meskipun untuk kumpulan data yang lebih besar Anda kemungkinan akan melihat kinerja yang lebih baik jika Anda menggunakan bahasa yang lebih kuat seperti awk, python, dll.Jika Anda merasa yakin, Anda dapat menghindari
for
pengulangan dengan menggunakanprintf
kemampuan untuk mendaur ulang formatnya untuk beberapa argumen, meskipun ini tampaknya membutuhkaneval
. (Berhenti membaca sekarang jika Anda setuju dengan itu.)$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") ) $ declare -p b declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )
Alasan yang dibutuhkan oleh solusi ini
eval
adalah karena nilai array ditentukan sebelum pemisahan kata. Itu berarti bahwa output dari substitusi perintah dianggap sebagai kata tunggal daripada sekumpulan pasangan kunci = nilai.Meskipun ini menggunakan subkulit, ini hanya menggunakan bash bawaan untuk memproses nilai array. Pastikan untuk mengevaluasi penggunaan Anda
eval
dengan mata kritis. Jika Anda tidak 100% yakin bahwa chepner atau glenn jackman atau greycat tidak akan menemukan kesalahan pada kode Anda, gunakan loop for sebagai gantinya.sumber
Saya menyadari ini sudah terjawab, tetapi muncul cukup tinggi dalam hasil penelusuran, dan mungkin membantu seseorang.
printf "%s\n" "${IDS[@]}" | sort -u
Contoh:
~> 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 ~>
sumber
ids=(ab "a a" ac aa ad ac aa);IFS=$'\n' ids2=(`printf "%s\n" "${ids[@]}" |sort -u`)
jadi saya menambahkanIFS=$'\n'
disarankan oleh @gniourf_gniourfIFS=$'\n'; ids2=(...)
karena penugasan sementara sebelum penugasan variabel tidak dimungkinkan. Sebaliknya menggunakan konstruksi ini:IFS=$'\n' read -r -a ids2 <<<"$(printf "%s\n" "${ids[@]}" | sort -u)"
.Jika elemen array Anda memiliki spasi putih atau karakter khusus shell lainnya (dan dapatkah Anda yakin tidak?) Maka untuk menangkap yang pertama-tama (dan Anda harus selalu melakukan ini) ekspresikan array Anda dalam tanda kutip ganda! mis
"${a[@]}"
. Bash secara harfiah akan menafsirkan ini sebagai "setiap elemen array dalam argumen terpisah ". Dalam bash ini selalu berhasil, selalu.Kemudian, untuk mendapatkan array yang diurutkan (dan unik), kita harus mengubahnya menjadi format yang dipahami oleh sort dan dapat mengubahnya kembali menjadi elemen array bash. Ini adalah yang terbaik yang saya hasilkan:
eval a=($(printf "%q\n" "${a[@]}" | sort -u))
Sayangnya, ini gagal dalam kasus khusus dari array kosong, mengubah array kosong menjadi array 1 elemen kosong (karena printf memiliki 0 argumen tetapi masih mencetak seolah-olah memiliki satu argumen kosong - lihat penjelasannya). Jadi, Anda harus menangkapnya di jika atau sesuatu.
Penjelasan: Format% q untuk printf "shell lolos" dari argumen tercetak, seperti bash dapat dipulihkan dalam sesuatu seperti eval! Karena setiap elemen dicetak shell yang lolos pada barisnya sendiri, satu-satunya pemisah antar elemen adalah baris baru, dan penetapan larik mengambil setiap baris sebagai elemen, mengurai nilai yang lolos ke dalam teks literal.
misalnya
> a=("foo bar" baz) > printf "%q\n" "${a[@]}" 'foo bar' baz > printf "%q\n" ''
Eval diperlukan untuk menghapus setiap nilai yang masuk kembali ke dalam array.
sumber
uniq
bukansort -u
.uniq
tidak berfungsi dengan baik pada daftar yang tidak diurutkan, jadi harus selalu digunakan bersamasort
.'sort' dapat digunakan untuk mengurutkan keluaran for-loop:
for i in ${ids[@]}; do echo $i; done | sort
dan hilangkan duplikat dengan "-u":
for i in ${ids[@]}; do echo $i; done | sort -u
Akhirnya Anda bisa menimpa array Anda dengan elemen unik:
ids=( `for i in ${ids[@]}; do echo $i; done | sort -u` )
sumber
ids=( `for i in ${ids[@]}; do echo $i; done | uniq` )
yang ini juga akan menjaga ketertiban:
echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'
dan untuk mengubah larik asli dengan nilai unik:
ARRAY=($(echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'))
sumber
uniq
. Perlu diurutkan, di mana awk tidak, dan tujuan dari jawaban ini adalah untuk mempertahankan pengurutan saat input tidak diurutkan.Untuk membuat array baru yang terdiri dari nilai-nilai unik, pastikan array Anda tidak kosong, lalu lakukan salah satu hal berikut:
Hapus entri duplikat (dengan penyortiran)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | sort -u)
Hapus entri duplikat (tanpa penyortiran)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | awk '!x[$0]++')
Peringatan: Jangan mencoba melakukan sesuatu seperti
NewArray=( $(printf '%s\n' "${OriginalArray[@]}" | sort -u) )
. Ini akan merusak ruang.sumber
sort -u
menjadiuniq
.uniq
hanya menggabungkan baris duplikat yang berdekatan, jadi tidak sama denganawk '!x[$0]++'
.sumber
Tanpa kehilangan pemesanan asli:
uniques=($(tr ' ' '\n' <<<"${original[@]}" | awk '!u[$0]++' | tr '\n' ' '))
sumber
Jika Anda menginginkan solusi yang hanya menggunakan internal bash, Anda dapat mengatur nilai sebagai kunci dalam array asosiatif, lalu mengekstrak kunci:
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
Ini akan menghasilkan
sumber
Pilihan lain untuk menangani whitespace yang disematkan, adalah dengan null-delimit
printf
, membuat perbedaan dengansort
, lalu menggunakan loop untuk mengemasnya kembali ke dalam array: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)
Di akhir ini,
input
danoutput
berisi nilai yang diinginkan (urutan yang diberikan tidak penting):$ printf "%q\n" "${input[@]}" a b c $'d\ne' b c $'d\ne' $ printf "%q\n" "${output[@]}" a b c $'d\ne'
sumber
Bagaimana dengan variasi ini?
printf '%s\n' "${ids[@]}" | sort -u
sumber
sorted_arr=($(printf '%s\n' "${ids[@]}" | sort -u)
.Coba ini untuk mendapatkan nilai uniq untuk kolom pertama dalam file
awk -F, '{a[$1];}END{for (i in a)print i;}'
sumber
# 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
sumber