Un peu piraté, mais cela devrait le faire:
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
Pour enregistrer les résultats uniques triés dans un tableau, effectuez une affectation de tableau :
sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
Si votre shell prend en charge herestrings ( bash
devrait), vous pouvez épargner un echo
processus en le modifiant en:
tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '
Contribution:
ids=(aa ab aa ac aa ad)
Production:
aa ab ac ad
Explication:
"${ids[@]}"
- Syntaxe pour travailler avec des tableaux shell, qu'ils soient utilisés dans le cadre echo
ou dans un héritage. La @
partie signifie "tous les éléments du tableau"
tr ' ' '\n'
- Convertissez tous les espaces en nouvelles lignes. Parce que votre tableau est vu par shell comme des éléments sur une seule ligne, séparés par des espaces; et parce que sort s'attend à ce que l'entrée soit sur des lignes séparées.
sort -u
- trier et conserver uniquement les éléments uniques
tr '\n' ' '
- convertissez les nouvelles lignes que nous avons ajoutées précédemment en espaces.
$(...)
- Substitution de commande
- À part:
tr ' ' '\n' <<< "${ids[@]}"
est une façon plus efficace de faire:echo "${ids[@]}" | tr ' ' '\n'
uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"
printf
cette façon (donnez plus d'arguments que de chaînes de format)sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
. Sans les parenthèses supplémentaires, il le donnait sous forme de chaîne.... | uniq | ...
place de... | sort -u | ...
.uniq
supprime uniquement les doublons consécutifs . Dans l'exemple de cette réponse,sorted_unique_ids
finira par être identique à l'originalids
. Pour préserver l'ordre, essayez... | awk '!seen[$0]++'
. Voir également stackoverflow.com/questions/1444406/… .Si vous exécutez Bash version 4 ou supérieure (ce qui devrait être le cas dans n'importe quelle version moderne de Linux), vous pouvez obtenir des valeurs de tableau uniques dans bash en créant un nouveau tableau associatif contenant chacune des valeurs du tableau d'origine. Quelque chose comme ça:
$ 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
Cela fonctionne car dans n'importe quel tableau (associatif ou traditionnel, dans n'importe quelle langue), chaque clé ne peut apparaître qu'une seule fois. Lorsque la
for
boucle atteint la deuxième valeur deaa
ina[2]
, elle écrase la valeurb[aa]
initialement définie poura[0]
.Faire les choses en natif bash peut être plus rapide que d'utiliser des tubes et des outils externes comme
sort
etuniq
, bien que pour des ensembles de données plus volumineux, vous obtiendrez probablement de meilleures performances si vous utilisez un langage plus puissant comme awk, python, etc.Si vous vous sentez confiant, vous pouvez éviter la
for
boucle en utilisantprintf
la capacité de recycler son format pour plusieurs arguments, bien que cela semble être nécessaireeval
. (Arrêtez de lire maintenant si cela vous convient.)$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") ) $ declare -p b declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )
La raison pour laquelle cette solution nécessite
eval
est que les valeurs de tableau sont déterminées avant la division des mots. Cela signifie que la sortie de la substitution de commande est considérée comme un mot unique plutôt que comme un ensemble de paires clé = valeur.Bien que cela utilise un sous-shell, il utilise uniquement des composants intégrés bash pour traiter les valeurs du tableau. Assurez-vous d'évaluer votre utilisation d'
eval
un œil critique. Si vous n'êtes pas sûr à 100% que chepner, glenn jackman ou greycat ne trouveront aucun problème avec votre code, utilisez plutôt la boucle for.la source
Je me rends compte que cela a déjà été répondu, mais cela apparaît assez haut dans les résultats de recherche et cela pourrait aider quelqu'un.
printf "%s\n" "${IDS[@]}" | sort -u
Exemple:
~> 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 ~>
la source
ids=(ab "a a" ac aa ad ac aa);IFS=$'\n' ids2=(`printf "%s\n" "${ids[@]}" |sort -u`)
alors j'ai ajoutéIFS=$'\n'
suggéré par @gniourf_gniourfIFS=$'\n'; ids2=(...)
car une affectation temporaire avant les affectations de variables n'est pas possible. Au lieu d' utiliser cette construction:IFS=$'\n' read -r -a ids2 <<<"$(printf "%s\n" "${ids[@]}" | sort -u)"
.Si vos éléments de tableau ont un espace blanc ou tout autre caractère spécial du shell (et pouvez-vous être sûr qu'ils n'en ont pas?) Alors pour les capturer d'abord (et vous devriez toujours le faire), exprimez votre tableau entre guillemets! par exemple
"${a[@]}"
. Bash l'interprétera littéralement comme "chaque élément du tableau dans un argument séparé ". Dans bash, cela fonctionne toujours, toujours.Ensuite, pour obtenir un tableau trié (et unique), nous devons le convertir en un format que le tri comprend et pouvoir le reconvertir en éléments de tableau bash. C'est le meilleur que j'ai trouvé:
eval a=($(printf "%q\n" "${a[@]}" | sort -u))
Malheureusement, cela échoue dans le cas particulier du tableau vide, transformant le tableau vide en un tableau de 1 élément vide (car printf avait 0 argument mais s'imprime toujours comme s'il avait un argument vide - voir l'explication). Vous devez donc saisir cela dans un si ou quelque chose.
Explication: Le format% q pour printf "shell échappe" l'argument imprimé, de manière à ce que bash puisse récupérer dans quelque chose comme eval! Étant donné que chaque élément est imprimé avec échappement shell sur sa propre ligne, le seul séparateur entre les éléments est le saut de ligne et l'affectation du tableau prend chaque ligne comme un élément, analysant les valeurs échappées en texte littéral.
par exemple
> a=("foo bar" baz) > printf "%q\n" "${a[@]}" 'foo bar' baz > printf "%q\n" ''
L'éval est nécessaire pour supprimer l'échappement de chaque valeur retournant dans le tableau.
la source
uniq
place desort -u
.uniq
cela ne fonctionne pas correctement sur les listes non triées, il doit donc toujours être utilisé en combinaison avecsort
.'sort' peut être utilisé pour ordonner la sortie d'une boucle for:
for i in ${ids[@]}; do echo $i; done | sort
et éliminez les doublons avec "-u":
for i in ${ids[@]}; do echo $i; done | sort -u
Enfin, vous pouvez simplement écraser votre tableau avec les éléments uniques:
ids=( `for i in ${ids[@]}; do echo $i; done | sort -u` )
la source
ids=( `for i in ${ids[@]}; do echo $i; done | uniq` )
celui-ci préservera également l'ordre:
echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'
et pour modifier le tableau d'origine avec les valeurs uniques:
ARRAY=($(echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'))
la source
uniq
. Il a besoin d'un tri, là où awk n'en a pas, et l'intention de cette réponse est de conserver l'ordre lorsque l'entrée n'est pas triée.Pour créer un nouveau tableau composé de valeurs uniques, assurez-vous que votre tableau n'est pas vide, puis effectuez l'une des opérations suivantes:
Supprimer les entrées en double (avec tri)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | sort -u)
Supprimer les entrées en double (sans tri)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | awk '!x[$0]++')
Attention: n'essayez pas de faire quelque chose comme
NewArray=( $(printf '%s\n' "${OriginalArray[@]}" | sort -u) )
. Il se brisera sur les espaces.la source
sort -u
pour êtreuniq
.uniq
ne fusionne que les lignes en double adjacentes, donc ce n'est pas la même chose queawk '!x[$0]++'
.la source
Sans perdre la commande d'origine:
uniques=($(tr ' ' '\n' <<<"${original[@]}" | awk '!u[$0]++' | tr '\n' ' '))
la source
Si vous souhaitez une solution qui n'utilise que des composants internes bash, vous pouvez définir les valeurs en tant que clés dans un tableau associatif, puis extraire les clés:
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
Cela produira
la source
Une autre option pour traiter les espaces blancs incorporés consiste à délimiter par null avec
printf
, à faire une distinction avecsort
, puis à utiliser une boucle pour le remettre dans un tableau: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)
À la fin de cela,
input
etoutput
contiennent les valeurs souhaitées (l'ordre à condition n'est pas important):$ printf "%q\n" "${input[@]}" a b c $'d\ne' b c $'d\ne' $ printf "%q\n" "${output[@]}" a b c $'d\ne'
la source
Et cette variation?
printf '%s\n' "${ids[@]}" | sort -u
la source
sorted_arr=($(printf '%s\n' "${ids[@]}" | sort -u)
.Essayez ceci pour obtenir des valeurs uniq pour la première colonne du fichier
awk -F, '{a[$1];}END{for (i in a)print i;}'
la source
# 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
la source