¿Cómo eliminar la nueva línea agregada por readarray cuando se usa un delimitador?

9
VAR=a,b,c,d
# VAR=$(echo $VAR|tr -d '\n')
echo "[$VAR]"
readarray -td, ARR<<< "$VAR"
declare -p ARR

Resultado:

[a,b,c,d]
declare -a ARR=([0]="a" [1]="b" [2]="c" [3]=$'d\n')

¿Cómo puedo decir que readarrayno agregue la nueva línea final \n? ¿Cuál es el significado del último $símbolo?

usuario1156544
fuente

Respuestas:

12

El carácter implícito de la nueva línea final no se agrega por el readarraybuiltin incorporado, sino por el here-string ( <<<) de bash, vea ¿Por qué un bash here-string agrega un carácter de nueva línea final? . Puede deshacerse de eso imprimiendo la cadena sin usar la nueva línea printfy leerla sobre una técnica de sustitución de proceso< <()

readarray -td, ARR < <(printf '%s' "$VAR")
declare -p ARR

generaría correctamente ahora

declare -a ARR=([0]="a" [1]="b" [2]="c" [3]="d")
Inian
fuente
3
¡Guauu! Nunca hubiera encontrado esto. Gracias
user1156544
4

Puede usar split + glob (lo que sucede cuando deja una expansión sin comillas en contextos de lista). Se interpone en nuestro camino la mayor parte del tiempo, sería una pena no usarlo cuando realmente lo necesitamos:

IFS=,
set -o noglob

ARR=($VAR) # split+glob with glob disabled, and split using , as delimiter

Eso es un poco menos complicado que escribir un archivo temporal y luego invocarlo readarraycomo en el readarray <<< "$string"enfoque (también tenga en cuenta que readarray -dnecesita una versión muy reciente de bash).

Tenga en cuenta que a pesar de Sin IFS(que significa separador ), eso funciona de la misma manera readarrayque a,,b,se divide en "a", ""y "b"solo.

Para un operador de división real, puede usar zshen su lugar:

ARR=("${(@s:,:)VAR}")

(las @comillas dobles y para preservar los elementos vacíos).

Stéphane Chazelas
fuente
¿ readarray <<< "$string"Escribe en un archivo tempp y luego lo elimina en lugar de usar la memoria?
user1156544
@ user1156544 Sí.
mosvy
¿Cómo puedo hacer algo similar a tu último comando en bash? Estoy usando bash 3.3 y estoy tratando de compensar la falta dereadarray -d
user1156544
3

Una versión enlatada de la respuesta de @ StéphaneChazelas:

# usage: setarray varname sep string
setarray(){ declare -n a=$1; local IFS=$2 -; set -f; a=($3); }

$ setarray arr , 1,2,3,
$ declare -p arr
declare -a arr=([0]="1" [1]="2" [2]="3")

$ setarray path : "$PATH"
$ setarray ld_preload ': ' "$LD_PRELOAD" # its elements can be separated by either ':' or spaces
...

El local -hará que las opciones como set -f( noglob) sean locales a la función, solo como variables.

El declare -n a=$1creará una variable locala como un alias a la variable global nombrada por $1(el primer argumento de la función).

Mosvy
fuente