Un poco hacky, pero esto debería funcionar:
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
Para guardar los resultados únicos ordenados nuevamente en una matriz, realice la asignación de matriz :
sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
Si su shell admite estas cadenas ( bash
debería), puede ahorrar un echo
proceso modificándolo a:
tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '
Entrada:
ids=(aa ab aa ac aa ad)
Salida:
aa ab ac ad
Explicación:
"${ids[@]}"
- Sintaxis para trabajar con matrices de shell, ya sea que se utilicen como parte echo
o como una cadena. La @
parte significa "todos los elementos de la matriz"
tr ' ' '\n'
- Convertir todos los espacios en nuevas líneas. Debido a que shell ve su matriz como elementos en una sola línea, separados por espacios; y porque sort espera que la entrada esté en líneas separadas.
sort -u
- ordenar y retener solo elementos únicos
tr '\n' ' '
- convertir las líneas nuevas que agregamos anteriormente en espacios.
$(...)
- Sustitución de mando
- Aparte:
tr ' ' '\n' <<< "${ids[@]}"
es una forma más eficiente de hacer:echo "${ids[@]}" | tr ' ' '\n'
uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"
printf
de esa manera (dar más argumentos que las cadenas de formato)sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
. Sin los paréntesis adicionales, lo estaba dando como una cadena.... | uniq | ...
lugar de... | sort -u | ...
.uniq
solo elimina los duplicados consecutivos . En el ejemplo de esta respuesta,sorted_unique_ids
terminará idéntico al originalids
. Para preservar el orden, inténtelo... | awk '!seen[$0]++'
. Consulte también stackoverflow.com/questions/1444406/… .Si está ejecutando Bash versión 4 o superior (que debería ser el caso en cualquier versión moderna de Linux), puede obtener valores de matriz únicos en bash creando una nueva matriz asociativa que contenga cada uno de los valores de la matriz original. Algo como esto:
$ 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
Esto funciona porque en cualquier matriz (asociativa o tradicional, en cualquier idioma), cada clave solo puede aparecer una vez. Cuando el
for
bucle llega al segundo valor deaa
ina[2]
, sobrescribe elb[aa]
que se estableció originalmentea[0]
.Hacer cosas en bash nativo puede ser más rápido que usar tuberías y herramientas externas como
sort
yuniq
, aunque para conjuntos de datos más grandes, probablemente verá un mejor rendimiento si usa un lenguaje más poderoso como awk, python, etc.Si se siente seguro, puede evitar el
for
bucle usandoprintf
la capacidad de reciclar su formato para múltiples argumentos, aunque esto parece ser necesarioeval
. (Deja de leer ahora si estás de acuerdo con eso).$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") ) $ declare -p b declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )
La razón por la que esta solución requiere
eval
es que los valores de la matriz se determinen antes de la división de palabras. Eso significa que la salida de la sustitución del comando se considera una sola palabra lugar de un conjunto de pares clave = valor.Si bien esto usa una subcapa, solo usa elementos internos de bash para procesar los valores de la matriz. Asegúrese de evaluar su uso
eval
con ojo crítico. Si no está 100% seguro de que chepner, glenn jackman o greycat no encontrarán fallas en su código, use el bucle for en su lugar.fuente
Me doy cuenta de que esto ya fue respondido, pero apareció bastante alto en los resultados de búsqueda y podría ayudar a alguien.
printf "%s\n" "${IDS[@]}" | sort -u
Ejemplo:
~> 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 ~>
fuente
ids=(ab "a a" ac aa ad ac aa);IFS=$'\n' ids2=(`printf "%s\n" "${ids[@]}" |sort -u`)
así que agregué loIFS=$'\n'
sugerido por @gniourf_gniourfIFS=$'\n'; ids2=(...)
ya que la asignación temporal antes de la asignación de variables no es posible. En lugar de utilizar esta construcción:IFS=$'\n' read -r -a ids2 <<<"$(printf "%s\n" "${ids[@]}" | sort -u)"
.Si los elementos de su matriz tienen espacios en blanco o cualquier otro carácter especial de shell (¿y puede estar seguro de que no lo tienen?), Entonces para capturarlos en primer lugar (y siempre debe hacer esto), exprese su matriz entre comillas dobles. ej
"${a[@]}"
. Bash literalmente interpretará esto como "cada elemento de la matriz en un argumento separado ". Dentro de bash esto simplemente siempre funciona, siempre.Luego, para obtener una matriz ordenada (y única), tenemos que convertirla a un formato que la ordenación comprenda y poder convertirla nuevamente en elementos de matriz bash. Esto es lo mejor que se me ocurrió:
eval a=($(printf "%q\n" "${a[@]}" | sort -u))
Desafortunadamente, esto falla en el caso especial de la matriz vacía, convirtiendo la matriz vacía en una matriz de 1 elemento vacío (porque printf tenía 0 argumentos pero aún se imprime como si tuviera un argumento vacío - ver explicación). Así que tienes que captar eso en un si o algo.
Explicación: El formato% q para printf "shell escapa" del argumento impreso, de tal manera que bash puede recuperarse en algo como eval! Debido a que cada elemento se imprime y se escapa en su propia línea, el único separador entre elementos es la nueva línea, y la asignación de matriz toma cada línea como un elemento, analizando los valores escapados en texto literal.
p.ej
> a=("foo bar" baz) > printf "%q\n" "${a[@]}" 'foo bar' baz > printf "%q\n" ''
La evaluación es necesaria para eliminar el escape de cada valor que regresa a la matriz.
fuente
uniq
lugar desort -u
.uniq
no funciona correctamente en listas sin clasificar, por lo que siempre debe usarse en combinación consort
.'sort' se puede usar para ordenar la salida de un bucle for:
for i in ${ids[@]}; do echo $i; done | sort
y elimine los duplicados con "-u":
for i in ${ids[@]}; do echo $i; done | sort -u
Finalmente, puede sobrescribir su matriz con los elementos únicos:
ids=( `for i in ${ids[@]}; do echo $i; done | sort -u` )
fuente
ids=( `for i in ${ids[@]}; do echo $i; done | uniq` )
este también preservará el orden:
echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'
y modificar la matriz original con los valores únicos:
ARRAY=($(echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'))
fuente
uniq
. Necesita ordenar, donde awk no lo hace, y la intención de esta respuesta es preservar el orden cuando la entrada no está ordenada.Para crear una nueva matriz que consta de valores únicos, asegúrese de que su matriz no esté vacía y luego realice una de las siguientes acciones:
Eliminar entradas duplicadas (con clasificación)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | sort -u)
Eliminar entradas duplicadas (sin clasificar)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | awk '!x[$0]++')
Advertencia: no intente hacer algo como
NewArray=( $(printf '%s\n' "${OriginalArray[@]}" | sort -u) )
. Se romperá en espacios.fuente
sort -u
a seruniq
.uniq
solo fusiona líneas duplicadas adyacentes, por lo que no es lo mismo queawk '!x[$0]++'
.fuente
Sin perder el pedido original:
uniques=($(tr ' ' '\n' <<<"${original[@]}" | awk '!u[$0]++' | tr '\n' ' '))
fuente
Si desea una solución que solo use componentes internos de bash, puede establecer los valores como claves en una matriz asociativa y luego extraer las claves:
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
Esto saldrá
fuente
Otra opción para tratar con espacios en blanco incrustados es delimitar nulo con
printf
, hacer distintivo consort
y luego usar un bucle para empaquetarlo nuevamente en una matriz: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)
Al final de esto,
input
youtput
contenga los valores deseados (el orden proporcionado no es importante):$ printf "%q\n" "${input[@]}" a b c $'d\ne' b c $'d\ne' $ printf "%q\n" "${output[@]}" a b c $'d\ne'
fuente
¿Qué tal esta variación?
printf '%s\n' "${ids[@]}" | sort -u
fuente
sorted_arr=($(printf '%s\n' "${ids[@]}" | sort -u)
.Intente esto para obtener valores uniq para la primera columna en el archivo
awk -F, '{a[$1];}END{for (i in a)print i;}'
fuente
# 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
fuente