140 votes

Linux bash : Assignation multiple de variables

Existe-t-il dans linux bash quelque chose de similaire au code suivant en PHP :

list($var1, $var2, $var3) = function_that_returns_a_three_element_array() ;

c'est-à-dire que vous attribuez en une seule phrase une valeur correspondante à 3 variables différentes.

Disons que j'ai la fonction bash myBashFuntion qui écrit sur stdout la chaîne "qwert asdfg zxcvb". Est-il possible de faire quelque chose comme :

(var1 var2 var3) = ( `myBashFuntion param1 param2` )

La partie à gauche du signe égal n'est pas une syntaxe valide, bien sûr. J'essaie simplement d'expliquer ce que je demande.

Ce qui fonctionne, en revanche, c'est ce qui suit :

array = ( `myBashFuntion param1 param2` )
echo ${array[0]} ${array[1]} ${array[2]}

Mais un tableau indexé n'est pas aussi descriptif que les noms de variables ordinaires.
Cependant, je pourrais juste faire :

var1 = ${array[0]} ; var2 = ${array[1]} ; var3 = ${array[2]}

Mais ce sont trois autres déclarations que je préférerais éviter.

Je cherche juste un raccourci syntaxique. Est-ce possible ?

256voto

La première chose qui me vient à l'esprit :

read -r a b c <<<$(echo 1 2 3) ; echo "$a|$b|$c"

Le résultat est, sans surprise

1|2|3

0 votes

C'est ce que je recherche, j'aime tellement SO ;-)

0 votes

Merci beaucoup, j'utilise ceci pour obtenir l'ip de la passerelle et le périphérique en une seule étape [code]read junk junk GWIP junk GWDEV <<$(ip route show 0.0.0.0/0)[/code]

4 votes

Est-il possible de faire en sorte que cela fonctionne si la première variable contient un espace ?

22voto

user3283321 Points 21

Je voulais affecter les valeurs à un tableau. Donc, en étendant L'approche de Michael Krelin Je l'ai fait :

read a[{1..3}] <<< $(echo 2 4 6); echo "${a[1]}|${a[2]}|${a[3]}"

ce qui donne :

2|4|6 

comme prévu.

2 votes

Pour mettre les valeurs dans un tableau, il existe déjà une solution simple que j'ai mentionnée dans la question : a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}

0 votes

Oui, j'avais négligé cela. Je dirais, cependant, que ma suggestion est mieux adaptée à l'affectation de tableaux plus grands.

0 votes

@soundray Votre solution utilise l'expansion et un herestring, bash étant ce qu'il est je doute qu'il soit performant dans ce scénario (mais je n'ai pas vérifié).

5voto

Otheus Points 71

Parfois, il faut faire quelque chose de funky. Disons que vous voulez lire une commande (l'exemple de la date par SDGuero par exemple) mais que vous voulez éviter les forks multiples.

read month day year << DATE_COMMAND
 $(date "+%m %d %Y")
DATE_COMMAND
echo $month $day $year

Vous pouvez également utiliser le pipe dans la commande de lecture, mais vous devrez alors utiliser les variables dans un sous-shell :

day=n/a; month=n/a; year=n/a
date "+%d %m %Y" | { read day month year ; echo $day $month $year; }
echo $day $month $year

résultats dans...

13 08 2013
n/a n/a n/a

0 votes

El read ne se passe pas dans un sous-shell à cause des accolades, c'est parce que vous avez la commande read sur le côté droit du pipe. Vous devez exécuter la commande read dans le shell actuel, ce que vous pouvez faire comme suit read day month year <<< `date "+%d %m %Y"`

0 votes

Non -- le read se produit mais la portée des variables qu'il lit tombe en dehors de la portée lorsque le sous-shell du pipeline se termine.

1 votes

Mon commentaire concernait la raison pourquoi la lecture se fait dans un sous-shell, et je réalise maintenant que j'ai mal interprété ce que tu as écrit. Je pensais que tu voulais dire que le sous-shell était créé parce que tu avais utilisé les accolades autour de l'instruction composée. Mais ! La raison pour laquelle tu as donné cet exemple était d'éviter le forking, et le subshell ne va-t-il pas forker aussi ?

4voto

SDGuero Points 88

Je pense que ça pourrait aider...

Afin de décomposer les dates saisies par l'utilisateur (mm/dd/yyyy) dans mes scripts, je stocke le jour, le mois et l'année dans un tableau, puis je place les valeurs dans des variables séparées comme suit :

DATE_ARRAY=(`echo $2 | sed -e 's/\// /g'`)
MONTH=(`echo ${DATE_ARRAY[0]}`)
DAY=(`echo ${DATE_ARRAY[1]}`)
YEAR=(`echo ${DATE_ARRAY[2]}`)

2 votes

Pourquoi ne pas éviter 4 sous-shells plus un processus sed supplémentaire, et faire tout cela en une seule ligne : IFS=/ read -r m d y < <(echo 12/29/2009)

0voto

pavium Points 7845

Le chapitre 5 du Livre de cuisine Bash de O'Reilly, discute (assez longuement) des raisons pour lesquelles l'affectation d'une variable ne doit pas comporter d'espace autour du signe "=".

MYVAR="something"

L'explication est liée à la distinction entre le nom d'une commande et d'une variable (où '=' peut être un argument valide).

Tout cela ressemble un peu à une justification a posteriori, mais en tout cas il n'est pas fait mention d'une méthode d'affectation à une liste de variables.

0 votes

Oui, je sais. J'ai juste ajouté des espaces supplémentaires ici et là pour plus de lisibilité.

0 votes

En effet, c'est une piètre motivation : Et si ' ; est un argument valable ? Lorsque j'écris ls ; cd il appelle toujours ls y cd malgré les espaces. Si je veux lister les répertoires appelés ; y cd Je peux juste taper ls ';' cd .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X