Como remover a nova linha adicionada pelo readarray ao usar um 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')

Como posso saber readarraypara não adicionar a nova linha final \n? Qual é o significado do último $símbolo?

user1156544
fonte

Respostas:

12

O caractere de nova linha à direita implícito não é adicionado pelo readarraybuilt-in, mas pela string here ( <<<) de bash, consulte Por que uma string aqui bash adiciona um caractere à nova linha à direita? . Você pode se livrar disso imprimindo a string sem a nova linha usando printfe lendo-a sobre uma técnica de substituição de processo< <()

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

geraria corretamente agora

declare -a ARR=([0]="a" [1]="b" [2]="c" [3]="d")
Inian
fonte
3
Uau! Eu nunca teria encontrado isso. Graças
user1156544
4

Você pode usar split + glob (o que acontece quando você deixa uma expansão sem aspas nos contextos da lista). Isso fica no nosso caminho na maioria das vezes, seria uma pena não usá-lo quando realmente precisamos:

IFS=,
set -o noglob

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

Isso é um pouco menos complicado do que escrever um arquivo temporário e depois invocá readarray-lo como na readarray <<< "$string"abordagem (observe também que readarray -dprecisa de uma versão muito recente bash).

Note-se que apesar do Sem IFS(que significa separação ), que funciona da mesma forma que readarrayna medida em que a,,b,é dividido em "a", ""e "b"única.

Para um operador de divisão real, você pode usar zsh:

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

( @aspas duplas e para preservar os elementos vazios).

Stéphane Chazelas
fonte
Ele readarray <<< "$string"grava em um arquivo tempp e o exclui em vez de usar a memória?
User1156544
@ user1156544 Sim.
mosvy
Como posso fazer algo semelhante ao seu último comando no bash? Eu estou usando o bash 3.3 e tentando compensar a falta dereadarray -d
user1156544
3

Uma versão em lata da resposta 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
...

O local -fará opções como set -f( noglob) local para a função, assim como variáveis.

O declare -n a=$1criará um local de variável acomo um alias para a variável global nomeada por $1(o primeiro argumento para a função).

mosvy
fonte