Comment supprimer la nouvelle ligne ajoutée par readarray lors de l'utilisation d'un délimiteur?

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

Résultat:

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

Comment puis-je dire de readarrayne pas ajouter la nouvelle ligne finale \n? Quelle est la signification du dernier $symbole?

user1156544
la source

Réponses:

13

Le caractère de fin de ligne implicite n'est pas ajouté par la fonction readarrayintégrée, mais par la chaîne here-string ( <<<) de bash, voir Pourquoi une chaîne bash here ajoute-t-elle un caractère de fin de ligne? . Vous pouvez vous en débarrasser en imprimant la chaîne sans utiliser la nouvelle ligne printfet en la lisant sur une technique de substitution de processus< <()

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

générerait correctement maintenant

declare -a ARR=([0]="a" [1]="b" [2]="c" [3]="d")
Inian
la source
3
Hou la la! Je n'aurais jamais trouvé ça. Merci
user1156544
4

Vous pouvez utiliser split + glob (ce qui se passe lorsque vous laissez une expansion sans guillemets dans des contextes de liste). Cela nous gêne la plupart du temps, il serait dommage de ne pas l'utiliser lorsque nous en avons réellement besoin:

IFS=,
set -o noglob

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

C'est un peu moins compliqué que d'écrire un fichier temporaire, puis de l'appeler readarraycomme dans l' readarray <<< "$string"approche (notez également qu'il readarray -dfaut une version très récente de bash).

Notez que malgré le Sdans IFS(qui signifie séparateur ), qui fonctionne de la même manière que readarraydans a,,b,c'est divisé en "a", ""et "b"seulement.

Pour un véritable opérateur de fractionnement, vous pouvez utiliser à la zshplace:

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

( @et les guillemets doubles pour conserver les éléments vides).

Stéphane Chazelas
la source
L' readarray <<< "$string"écrit dans un fichier tempp, puis le supprime au lieu d'utiliser la mémoire?
user1156544
@ user1156544 Oui.
mosvy
Comment puis-je faire quelque chose de similaire à votre dernière commande dans bash? J'utilise bash 3.3 et j'essaie de compenser le manque dereadarray -d
user1156544
3

Une version en conserve de la réponse 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
...

Le local -rendra les options comme set -f( noglob) locales à la fonction, tout comme les variables.

Le declare -n a=$1va créer une variable localea comme alias de la variable globale nommée par $1(le premier argument de la fonction).

mosvy
la source