Necesito eliminar un elemento de una matriz en bash shell. Generalmente, simplemente haría:
array=("${(@)array:#<element to remove>}")
Desafortunadamente, el elemento que quiero eliminar es una variable, por lo que no puedo usar el comando anterior. Aquí abajo un ejemplo:
array+=(pluto)
array+=(pippo)
delete=(pluto)
array( ${array[@]/$delete} ) -> but clearly doesn't work because of {}
¿Alguna idea?
zsh
.array=( ${array[@]/$delete} )
funciona como se esperaba en Bash. ¿Simplemente te has perdido el=
?Respuestas:
Lo siguiente funciona como le gustaría en
bash
yzsh
:Si necesita eliminar más de un elemento:
Consideración
Esta técnica en realidad elimina los prefijos que coinciden
$delete
con los elementos, no necesariamente elementos completos.Actualizar
Para eliminar realmente un elemento exacto, debe recorrer la matriz, comparar el objetivo con cada elemento y usar
unset
para eliminar una coincidencia exacta.Tenga en cuenta que si hace esto y se eliminan uno o más elementos, los índices ya no serán una secuencia continua de números enteros.
El simple hecho es que los arreglos no fueron diseñados para usarse como estructuras de datos mutables. Se utilizan principalmente para almacenar listas de elementos en una sola variable sin necesidad de desperdiciar un carácter como delimitador (por ejemplo, para almacenar una lista de cadenas que pueden contener espacios en blanco).
Si los huecos son un problema, entonces necesita reconstruir la matriz para llenar los huecos:
fuente
$ array=(sun sunflower)
$ delete=(sun)
$ echo ${array[@]/$delete}
resultados enflower
(pluto1 pluto2 pippo)
, terminará con(1 2 pippo)
.for element in "${array[@]}" do if [[ $element ]]; then echo ${element} fi done
Puede crear una nueva matriz sin el elemento no deseado y luego volver a asignarla a la matriz anterior. Esto funciona en
bash
:Esto produce:
fuente
Esta es la forma más directa de desarmar un valor si conoce su posición.
fuente
echo ${array[1]}
, obtendrás una cadena nula. Y para conseguirlothree
tienes que hacerloecho ${array[2]}
. Entonces,unset
no es el mecanismo correcto para eliminar un elemento en la matriz bash.${array[1]+x}
es una cadena nula, por lo que noarray[1]
está configurado.unset
no cambia los índices de los elementos restantes. No es necesario citar el argumento de unset. La forma de destruir un elemento de matriz se describe en el manual de Bash .${array[1]}
existe solo porque el tamaño es 2. Si desea los índices, marque${!array[@]}
.Aquí hay una solución de una línea con mapfile:
Ejemplo:
Este método permite una gran flexibilidad al modificar / intercambiar el comando grep y no deja cadenas vacías en la matriz.
fuente
printf '%s\n' "${array[@]}"
en lugar de esa feaIFS
/echo
cosa.-d $'\0'
funciona perfectamente bien mientras que-d
sin el argumento no lo hace.-d $'\0'
es lo mismo que-d $'\0 something'
o simplemente-d ''
.$'\0'
embargoEsta respuesta es específica para el caso de eliminar varios valores de matrices grandes, donde el rendimiento es importante.
Las soluciones más votadas son (1) sustitución de patrones en una matriz, o (2) iterar sobre los elementos de la matriz. El primero es rápido, pero solo puede tratar con elementos que tienen un prefijo distinto, el segundo tiene O (n * k), n = tamaño de matriz, k = elementos para eliminar. La matriz asociativa es una característica relativamente nueva y es posible que no haya sido común cuando se publicó originalmente la pregunta.
Para el caso de coincidencia exacta, con n y k grandes, es posible mejorar el rendimiento de O (n k) a O (n + k log (k)). En la práctica, O (n) asumiendo k mucho menor que n. La mayor parte de la aceleración se basa en el uso de una matriz asociativa para identificar los elementos que se eliminarán.
Rendimiento (tamaño de matriz n, valores k para eliminar). Segundos de medición del rendimiento del tiempo del usuario
Como era de esperar, la
current
solución es lineal a N * K, y lafast
solución es prácticamente lineal a K, con una constante mucho más baja. Lafast
solución es un poco más lenta que lacurrent
solución cuando k = 1, debido a una configuración adicional.La solución 'Rápida': matriz = lista de entrada, eliminar = lista de valores para eliminar.
Comparado con la
current
solución, a partir de la respuesta más votada.fuente
Aquí hay una pequeña función (probablemente muy específica de bash) que involucra direccionamiento indirecto de variables bash y
unset
; es una solución general que no implica la sustitución de texto ni el descarte de elementos vacíos y no tiene problemas con las citas / espacios en blanco, etc.Úselo como
delete_ary_elmt ELEMENT ARRAYNAME
sin ningún$
sigilo. Cambie== $word
por== $word*
para coincidencias de prefijo; utilizar${elmt,,} == ${word,,}
para coincidencias que no distinguen entre mayúsculas y minúsculas; etc., lo que sea que[[
soporte bash .Funciona determinando los índices de la matriz de entrada e iterando sobre ellos hacia atrás (por lo que eliminar elementos no arruina el orden de iteración). Para obtener los índices, debe acceder a la matriz de entrada por nombre, lo que se puede hacer a través de la indirección de la variable bash
x=1; varname=x; echo ${!varname} # prints "1"
.No puede acceder a las matrices por nombre como
aryname=a; echo "${$aryname[@]}
, esto le da un error. No puede hacerloaryname=a; echo "${!aryname[@]}"
, esto le da los índices de la variablearyname
(aunque no es una matriz). Lo que SÍ funciona esaryref="a[@]"; echo "${!aryref}"
que imprimirá los elementos de la matriza
, conservando las citas de palabras de shell y los espacios en blanco exactamente comoecho "${a[@]}"
. Pero esto sólo funciona para la impresión de los elementos de una matriz, no para la impresión de su longitud o índices (aryref="!a[@]"
oaryref="#a[@]"
, o"${!!aryref}"
, o"${#!aryref}"
, todas fallan).Así que copio la matriz original por su nombre a través de bash indirección y obtengo los índices de la copia. Para iterar sobre los índices a la inversa, utilizo un bucle for estilo C. También podría hacerlo accediendo a los índices a través de
${!arycopy[@]}
e invirtiéndolos contac
, que es un cambiocat
en el orden de la línea de entrada.Una solución de función sin indirección variable probablemente tendría que involucrar
eval
, lo que puede o no ser seguro de usar en esa situación (no puedo decirlo).fuente
delete_ary_elmt "d" array
y luego volver a imprimir la matriz. Verá que se elimina el elemento incorrecto. La eliminación del último elemento tampoco funcionará.Para ampliar las respuestas anteriores, se puede usar lo siguiente para eliminar varios elementos de una matriz, sin una coincidencia parcial:
Esto resultará en una matriz que contiene: (dos uno dos tres tres cuatro "uno seis")
fuente
Si alguien se encuentra en una posición en la que necesita recordar los valores set -e o set -x y poder restaurarlos, consulte esta esencia que utiliza la primera solución de eliminación de matriz para administrar su propia pila:
https://gist.github.com/kigster/94799325e39d2a227ef89676eed44cc6
fuente
Solo respuesta parcial
Para eliminar el primer elemento de la matriz
Para eliminar el último elemento de la matriz
fuente
unset
.array0
en el directorio actual, dado quearray[0]
es glob, primero se expandiráarray0
antes del comando unset.Utilizando
unset
Para eliminar un elemento en un índice particular, podemos usar
unset
y luego copiar a otra matriz.unset
En este caso, solo no se requiere. Debido aunset
que no elimina el elemento, simplemente establece una cadena nula para el índice particular en la matriz.La salida es
Utilizando
:<idx>
Podemos eliminar algún conjunto de elementos usando
:<idx>
también. Por ejemplo, si queremos eliminar el primer elemento, podemos usarlo:1
como se menciona a continuación.La salida es
fuente
El script de shell POSIX no tiene matrices.
Así que lo más probable es que estés usando un dialecto específico, como
bash
korn shells ozsh
.Por lo tanto, su pregunta a partir de ahora no puede tener respuesta.
Quizás esto funcione para ti:
fuente
En realidad, acabo de notar que la sintaxis del shell tiene un comportamiento incorporado que permite una fácil reconstrucción de la matriz cuando, como se plantea en la pregunta, se debe eliminar un elemento.
¿Observa cómo construimos la matriz usando la
x+=()
sintaxis de bash ?De hecho, podría agregar más de un elemento con eso, el contenido de una matriz completamente diferente a la vez.
fuente
http://wiki.bash-hackers.org/syntax/pe#substring_removal
Para hacer un elemento de eliminación completo, debe hacer un comando de desarmado con una declaración if. Si no le importa eliminar los prefijos de otras variables o admitir espacios en blanco en la matriz, puede soltar las comillas y olvidarse de los bucles for.
Vea el ejemplo a continuación para conocer algunas formas diferentes de limpiar una matriz.
Salida
Espero que ayude.
fuente
En ZSH esto es muy fácil (tenga en cuenta que esto usa más sintaxis compatible con bash de la necesaria cuando sea posible para facilitar la comprensión):
Resultados:
fuente
También existe esta sintaxis, por ejemplo, si desea eliminar el segundo elemento:
que es de hecho la concatenación de 2 pestañas. El primero del índice 0 al índice 1 (exclusivo) y el segundo del índice 2 al final.
fuente
Lo que hago es:
BAM, ese artículo se elimina.
fuente
array=('first item' 'second item')
.Esta es una solución rápida y sucia que funcionará en casos simples pero se romperá si (a) hay caracteres especiales de expresiones regulares
$delete
o (b) hay espacios en todos los elementos. Empezando con:Elimine todas las entradas que coincidan exactamente
$delete
:resultando en
echo $array
-> pippo, y asegurándose de que sea una matriz:echo $array[1]
-> pippofmt
es un poco oscuro: sefmt -1
ajusta a la primera columna (para poner cada elemento en su propia línea. Ahí es donde surge el problema con los elementos en los espacios). Lofmt -999999
desenvuelve en una línea, volviendo a colocar los espacios entre los elementos. Hay otras formas de hacerlo, comoxargs
.Anexo: si desea eliminar solo la primera coincidencia, use sed, como se describe aquí :
fuente
¿Qué tal algo como:
fuente
Para evitar conflictos con el uso de índice de matriz
unset
- ver https://stackoverflow.com/a/49626928/3223785 y https://stackoverflow.com/a/47798640/3223785 para más información - reasignar la matriz a sí mismo:ARRAY_VAR=(${ARRAY_VAR[@]})
.[Ref .: https://tecadmin.net/working-with-array-bash-script/ ]
fuente
fuente