Tengo file.txt que necesito leer en una matriz Bash. Luego, necesito eliminar los espacios, las comillas dobles y todo menos la primera coma en cada entrada . Esto es lo lejos que he llegado:
$ cat file.txt 10,this 2 0 , i s 30,"all" 40,I 50,n,e,e,d,2 60",s e,e" $ cat script.sh #!/bin/bash readarray -t ARRAY<$1 ARRAY=( "${ARRAY[@]// /}" ) ARRAY=( "${ARRAY[@]//\"/}" ) for ELEMENT in "${ARRAY[@]}";do echo "|ELEMENT|$ELEMENT|" done $ ./script.sh file.txt |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,n,e,e,d,2| |ELEMENT|60,se,e|
Lo cual funciona muy bien excepto por la situación de la coma. Soy consciente de que hay varias formas de desollar a este gato, pero debido a la secuencia de comandos más grande del que forma parte, realmente me gustaría usar la sustitución de parámetros para llegar aquí:
|ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
¿Es esto posible mediante la sustitución de parámetros?
Comentarios
- ¿Hay alguna razón por la que deba mantener el texto en una matriz, y por qué no puedes ‘ dejar, por ejemplo,
awk
osed
¿procesan los datos? - @Jeff – El bucle sobre la matriz será un pesadilla para implementar en el script más grande en el que ‘ estoy trabajando.
- @JonRed No ‘ no sé qué que está haciendo, por lo que ‘ es completamente posible que no tenga otra opción en el asunto, pero en general, cuando se encuentra haciendo acrobacias de cuerdas tan complejas en el caparazón, que ‘ es una muy buena indicación de que debería utilizar un lenguaje de programación real. El shell no está diseñado como un lenguaje de programación, y aunque se puede usar como tal, realmente no es ‘ t una buena idea para cosas más complejas. Le recomiendo encarecidamente que considere cambiar a perl o python o cualquier otro lenguaje de programación.
- @terdon Es ‘ s gracioso, acabo de decir casi lo exacto lo mismo a mi colega antes de leer esta publicación. Básicamente dije que esta es la versión final de este script y que cualquier requisito adicional necesitará reescribirlo en Perl. Así que sí, definitivamente estoy de acuerdo
Responder
Quitaría lo que necesita quitar usando sed
antes de cargar en la matriz (también tenga en cuenta los nombres de las variables en minúsculas, en general es mejor evitar las variables en mayúsculas en los scripts de shell):
#!/bin/bash readarray -t array< <(sed "s/"//g; s/ *//g; s/,/"/; s/,//g; s/"/,/" "$1") for element in "${array[@]}";do echo "|ELEMENT|$element|" done
Esto produce la siguiente salida en su archivo de ejemplo:
$ foo.sh file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
Si realmente debe usar el parámetro sustitución, intente algo como esto:
#!/bin/bash readarray -t array< "$1" array=( "${array[@]// /}" ) array=( "${array[@]//\"/}" ) array=( "${array[@]/,/\"}" ) array=( "${array[@]//,/}" ) array=( "${array[@]/\"/,}" ) for element in "${array[@]}"; do echo "|ELEMENT|$element|" done
Comentarios
Respuesta
Por lo que puedo ver, no es necesario léelo en una matriz bash
para crear esa salida:
$ sed "s/[ "]//g; s/,/ /; s/,//g; s/ /,/; s/.*/|ELEMENT|&|/" <file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
La sed
expresión elimina espacios y comillas dobles, reemplaza la primera coma con un espacio (no hay otros espacios en la cadena en este punto), elimina todas las demás comas, restaura la primera coma y antepone y agrega los datos adicionales .
Alternativamente, con GNU sed
:
sed "s/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/" <file
(estándar sed
no admite la combinación de 2
y g
como indicadores para s
comando).
Comentarios
- con GNU sed, puede usar
's/,//2g
para eliminar las comas, comenzando con el segundo - Y, los últimos 2 s /// comandos pueden ser
s/.*/|ELEMENT|&|/
pero eso puede ser más esfuerzo para sed. - @glennjackman Posiblemente, pero se ve bastante ordenado.
- Sí, esto es parte de un script más grande. La matriz es necesaria, no solo para la salida. De ahí mi interés en la sustitución de parámetros. Podría recorrer la matriz con esto, pero será una pesadilla de implementar. Terndon proporcionó una solución sin bucles utilizando sed a la que ‘ probablemente recurriré si la sustitución de parámetros no es válida.
- Si no estaba ‘ t vinculado al uso de una matriz, sin embargo, esta sería la mejor solución.
Respuesta
ELEMENT="50,n,e,e,d,2" IFS=, read -r first rest <<<"$ELEMENT" printf "%s,%s\n" "$first" "${rest//,/}"
50,need2
Olvídese del hábito de usar nombres de variables ALLCAPS. Eventualmente chocará con una variable crucial del «sistema» como PATH y romperá su código.
Comentarios
- Sin sustitución de parámetros. PERO, no sabía que los nombres de las variables ALLCAPS eran un mal hábito en Bash. Tienes un buen punto, uno que definitivamente confirma una búsqueda superficial en Google. ¡Gracias por mejorar mi estilo! 🙂
- Yo ‘ he respondido preguntas en las que la persona escribió
PATH=something; ls $PATH
y luego se preguntó sobre ells: command not found
error. - Hay casi un centenar de variables integradas que se nombran en mayúsculas (haga clic en esta página de manual enlace ) para ver …
Respuesta
[Esta es esencialmente una versión más completa versión de respuesta de glenn jackmann ]
Construyendo una matriz asociativa a partir de la clave y el valor despojados, usando la primera coma como separador:
declare -A arr while IFS=, read -r k v; do arr["${k//[ \"]}"]="${v//[ ,\"]}"; done < file.txt for k in "${!arr[@]}"; do printf "|ELEMENT|%s,%s|\n" "$k" "${arr[$k]}" done |ELEMENT|20,is| |ELEMENT|10,this| |ELEMENT|50,need2| |ELEMENT|40,I| |ELEMENT|60,see| |ELEMENT|30,all|
Respuesta
Puede recorrer la matriz y usar una variable intermedia:
for((i=0; i < "${#ARRAY[@]}"; i++)) do rest="${ARRAY[i]#*,}" ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}" done
Esto asigna a rest
la parte después de la primera coma; luego concatenamos tres piezas de nuevo en el original variable:
- la parte antes de la primera coma
- una coma
- el reemplazo en
rest
de cada coma sin nada
Comentarios
- Este fue mi primer pensamiento y es bastante simple para el ejemplo, pero esto es parte de un script más grande donde la matriz es masiva y hay ‘ s ya bucles y sería una cosa completa. Esto definitivamente funcionaría, pero sería muy complicado de implementar en el proyecto más grande en el que ‘ estoy trabajando.
- Bastante justo; Intenté responder dentro de las limitaciones (solo expansión de parámetros).
RANDOMTEXTTHATWILLNEVERBEINTHEFILE
.