J'ai besoin de supprimer un élément d'un tableau dans le shell bash. En général, je ferais simplement:
array=("${(@)array:#<element to remove>}")
Malheureusement, l'élément que je souhaite supprimer est une variable, je ne peux donc pas utiliser la commande précédente. Ci-dessous un exemple:
array+=(pluto)
array+=(pippo)
delete=(pluto)
array( ${array[@]/$delete} ) -> but clearly doesn't work because of {}
Une idée?
zsh
.array=( ${array[@]/$delete} )
fonctionne comme prévu dans Bash. Avez-vous simplement manqué le=
?Réponses:
Ce qui suit fonctionne comme vous le souhaitez
bash
etzsh
:Si besoin de supprimer plus d'un élément:
Caveat
Cette technique supprime en fait les préfixes correspondants
$delete
des éléments, pas nécessairement des éléments entiers.Mettre à jour
Pour vraiment supprimer un élément exact, vous devez parcourir le tableau, comparer la cible à chaque élément et utiliser
unset
pour supprimer une correspondance exacte.Notez que si vous faites cela et qu'un ou plusieurs éléments sont supprimés, les indices ne seront plus une séquence continue d'entiers.
Le fait est que les tableaux n'ont pas été conçus pour être utilisés en tant que structures de données mutables. Ils sont principalement utilisés pour stocker des listes d'éléments dans une seule variable sans avoir besoin de gaspiller un caractère comme délimiteur (par exemple, pour stocker une liste de chaînes pouvant contenir des espaces).
Si les lacunes sont un problème, vous devez reconstruire la matrice pour combler les lacunes:
la source
$ array=(sun sunflower)
$ delete=(sun)
$ echo ${array[@]/$delete}
résultatsflower
(pluto1 pluto2 pippo)
ça, vous vous retrouverez avec(1 2 pippo)
.for element in "${array[@]}" do if [[ $element ]]; then echo ${element} fi done
Vous pouvez créer un nouveau tableau sans l'élément indésirable, puis le réattribuer à l'ancien tableau. Cela fonctionne dans
bash
:Cela donne:
la source
C'est le moyen le plus direct d'annuler une valeur si vous connaissez sa position.
la source
echo ${array[1]}
, vous obtiendrez une chaîne nulle. Et pour y arriver,three
vous devez le faireecho ${array[2]}
. Ceunset
n'est donc pas le bon mécanisme pour supprimer un élément dans un tableau bash.${array[1]+x}
est une chaîne nulle, doncarray[1]
non définie.unset
ne modifie pas les index des éléments restants. Il n'est pas nécessaire de citer l'argument pour unset. La manière de détruire un élément de tableau est décrite dans le manuel de Bash .${array[1]}
existe simplement parce que la taille est de 2. Si vous voulez les indices, vérifiez${!array[@]}
.Voici une solution en une ligne avec mapfile:
Exemple:
Cette méthode permet une grande flexibilité en modifiant / échangeant la commande grep et ne laisse aucune chaîne vide dans le tableau.
la source
printf '%s\n' "${array[@]}"
place de ce mocheIFS
/echo
chose.-d $'\0'
fonctionne parfaitement bien alors que juste-d
sans l'argument ne fonctionne pas.-d $'\0'
est identique-d $'\0 something'
ou juste-d ''
.$'\0'
pour plus de clartéCette réponse est spécifique au cas de la suppression de plusieurs valeurs de grands tableaux, où les performances sont importantes.
Les solutions les plus votées sont (1) la substitution de motif sur un tableau, ou (2) l'itération sur les éléments du tableau. Le premier est rapide, mais ne peut traiter que des éléments qui ont un préfixe distinct, le second a O (n * k), n = taille du tableau, k = éléments à supprimer. Les tableaux associatifs sont une nouvelle fonctionnalité relative et peuvent ne pas avoir été courants lorsque la question a été initialement publiée.
Pour le cas de correspondance exacte, avec n et k grands, il est possible d'améliorer les performances de O (n k) à O (n + k log (k)). En pratique, O (n) en supposant que k bien inférieur à n. La plupart de l'accélération repose sur l'utilisation d'un tableau associatif pour identifier les éléments à supprimer.
Performances (taille n-array, valeurs k à supprimer). Mesure des performances en secondes de temps utilisateur
Comme prévu, la
current
solution est linéaire à N * K, et lafast
solution est pratiquement linéaire à K, avec une constante beaucoup plus faible. Lafast
solution est légèrement plus lente que lacurrent
solution lorsque k = 1, en raison d'une configuration supplémentaire.La solution 'Rapide': array = liste des entrées, delete = liste des valeurs à supprimer.
Comparé à la
current
solution, d'après la réponse la plus votée.la source
Voici une petite fonction (probablement très spécifique à bash) impliquant l'indirection de variable bash et
unset
; c'est une solution générale qui n'implique pas de substitution de texte ou de suppression d'éléments vides et qui n'a aucun problème avec les guillemets / les espaces, etc.Utilisez-le comme
delete_ary_elmt ELEMENT ARRAYNAME
sans aucun$
sceau. Commutez le== $word
for== $word*
pour les correspondances de préfixe; utiliser${elmt,,} == ${word,,}
pour les correspondances insensibles à la casse; etc., tout ce que bash[[
prend en charge.Cela fonctionne en déterminant les indices du tableau d'entrée et en les itérant à l'envers (la suppression d'éléments ne gâche donc pas l'ordre d'itération). Pour obtenir les indices, vous devez accéder au tableau d'entrée par nom, ce qui peut être fait via l'indirection de variable bash
x=1; varname=x; echo ${!varname} # prints "1"
.Vous ne pouvez pas accéder aux tableaux par nom comme
aryname=a; echo "${$aryname[@]}
, cela vous donne une erreur. Vous ne pouvez pas fairearyname=a; echo "${!aryname[@]}"
, cela vous donne les indices de la variablearyname
(bien que ce ne soit pas un tableau). Ce qui fonctionnearyref="a[@]"; echo "${!aryref}"
, c'est imprimer les éléments du tableaua
, en préservant exactement les guillemets et les espaces blancsecho "${a[@]}"
. Mais cela ne fonctionne que pour imprimer les éléments d'un tableau, pas pour imprimer sa longueur ou ses indices (aryref="!a[@]"
ouaryref="#a[@]"
ou"${!!aryref}"
ou"${#!aryref}"
, ils échouent tous).Je copie donc le tableau d'origine par son nom via l'indirection bash et récupère les indices de la copie. Pour parcourir les indices en sens inverse, j'utilise une boucle for de style C. Je pourrais aussi le faire en accédant aux index via
${!arycopy[@]}
et en les inversant avectac
, cecat
qui tourne autour de l'ordre des lignes d'entrée.Une solution de fonction sans indirection variable devrait probablement impliquer
eval
, ce qui peut ou non être sûr à utiliser dans cette situation (je ne peux pas le dire).la source
delete_ary_elmt "d" array
puis de réimprimer la matrice. Vous verrez que le mauvais élément est supprimé. La suppression du dernier élément ne fonctionnera donc jamais non plus.Pour développer les réponses ci-dessus, les éléments suivants peuvent être utilisés pour supprimer plusieurs éléments d'un tableau, sans correspondance partielle:
Cela se traduira par un tableau contenant: (deux un deux trois trois quatre "un six")
la source
Si quelqu'un se trouve dans une position où il doit se souvenir des valeurs set -e ou set -x et être en mesure de les restaurer, veuillez consulter l'essentiel qui utilise la première solution de suppression de tableau pour gérer sa propre pile:
https://gist.github.com/kigster/94799325e39d2a227ef89676eed44cc6
la source
Réponse partielle uniquement
Pour supprimer le premier élément du tableau
Pour supprimer le dernier élément du tableau
la source
unset
.array0
dans le répertoire courant, alors commearray[0]
est glob, il sera d'abord développéarray0
avant la commande unset.En utilisant
unset
Pour supprimer un élément à un index particulier, nous pouvons utiliser
unset
puis copier dans un autre tableau. Seulement justeunset
n'est pas nécessaire dans ce cas. Commeunset
ne supprime pas l'élément, il définit simplement une chaîne nulle sur l'index particulier du tableau.La sortie est
En utilisant
:<idx>
Nous pouvons supprimer un ensemble d'éléments en utilisant
:<idx>
également. Par exemple, si nous voulons supprimer le 1er élément, nous pouvons utiliser:1
comme mentionné ci-dessous.La sortie est
la source
Le script shell POSIX n'a pas de tableaux.
Donc, très probablement, vous utilisez un dialecte spécifique tel que
bash
, korn shells ouzsh
.Par conséquent, vous ne pouvez pas répondre à votre question pour le moment.
Peut-être que cela fonctionne pour vous:
la source
En fait, je viens de remarquer que la syntaxe du shell a quelque peu un comportement intégré qui permet une reconstruction facile du tableau lorsque, comme posé dans la question, un élément doit être supprimé.
Remarquez comment nous avons construit le tableau en utilisant la
x+=()
syntaxe de bash ?Vous pouvez en fait ajouter plus d'un élément avec cela, le contenu d'un tout autre tableau à la fois.
la source
http://wiki.bash-hackers.org/syntax/pe#substring_removal
Afin de faire un élément de suppression complet, vous devez exécuter une commande unset avec une instruction if. Si vous ne vous souciez pas de supprimer les préfixes d'autres variables ou de prendre en charge les espaces dans le tableau, vous pouvez simplement laisser tomber les guillemets et oublier les boucles for.
Consultez l'exemple ci-dessous pour découvrir différentes façons de nettoyer une baie.
Production
J'espère que cela pourra aider.
la source
Dans ZSH, c'est extrêmement simple (notez que cela utilise plus de syntaxe compatible bash que nécessaire lorsque cela est possible pour faciliter la compréhension):
Résultats:
la source
Il existe également cette syntaxe, par exemple si vous souhaitez supprimer le 2ème élément:
qui est en fait la concaténation de 2 onglets. Le premier de l'index 0 à l'index 1 (exclusif) et le second de l'index 2 à la fin.
la source
Ce que je fais c'est:
BAM, cet élément est supprimé.
la source
array=('first item' 'second item')
.C'est une solution rapide et sale qui fonctionnera dans des cas simples mais qui se cassera si (a) il y a des caractères spéciaux regex dans
$delete
, ou (b) il y a des espaces dans n'importe quel élément. Commençant par:Supprimez toutes les entrées correspondant exactement
$delete
:résultant en
echo $array
-> pippo, et en s'assurant que c'est un tableau:echo $array[1]
-> pippofmt
est un peu obscur:fmt -1
s'enroule à la première colonne (pour mettre chaque élément sur sa propre ligne. C'est là que le problème se pose avec les éléments dans les espaces.) lefmt -999999
déroule en une ligne, en remettant les espaces entre les éléments. Il existe d'autres moyens de le faire, par exemplexargs
.Addendum: Si vous souhaitez supprimer uniquement la première correspondance, utilisez sed, comme décrit ici :
la source
Que diriez-vous de quelque chose comme:
la source
Pour éviter les conflits avec l' index de tableau à l' aide
unset
- voir https://stackoverflow.com/a/49626928/3223785 et https://stackoverflow.com/a/47798640/3223785 pour plus d' informations - réattribuer le tableau à lui - même:ARRAY_VAR=(${ARRAY_VAR[@]})
.[Réf.: Https://tecadmin.net/working-with-array-bash-script/ ]
la source
la source