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
bashyzsh:Si necesita eliminar más de un elemento:
Consideración
Esta técnica en realidad elimina los prefijos que coinciden
$deletecon 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
unsetpara 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 donePuede 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 conseguirlothreetienes que hacerloecho ${array[2]}. Entonces,unsetno 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.unsetno 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/echocosa.-d $'\0'funciona perfectamente bien mientras que-dsin 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
currentsolución es lineal a N * K, y lafastsolución es prácticamente lineal a K, con una constante mucho más baja. Lafastsolución es un poco más lenta que lacurrentsolució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
currentsolució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 ARRAYNAMEsin ningún$sigilo. Cambie== $wordpor== $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 cambiocaten 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" arrayy 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.array0en el directorio actual, dado quearray[0]es glob, primero se expandiráarray0antes del comando unset.Utilizando
unsetPara eliminar un elemento en un índice particular, podemos usar
unsety luego copiar a otra matriz.unsetEn este caso, solo no se requiere. Debido aunsetque 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:1como 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
bashkorn 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
$deleteo (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]-> pippofmtes un poco oscuro: sefmt -1ajusta 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 -999999desenvuelve 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