Linux bash: asignación de múltiples variables

121

Existe en linux bash algo similar al siguiente código en PHP:

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

es decir, asigna en una oración un valor correspondiente a 3 variables diferentes.

Digamos que tengo la función bash myBashFuntionque escribe en stdout la cadena "qwert asdfg zxcvb". ¿Es posible hacer algo como:

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

Por supuesto, la parte a la izquierda del signo igual no es una sintaxis válida. Solo intento explicar lo que estoy pidiendo.

Sin embargo, lo que funciona es lo siguiente:

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

Pero una matriz indexada no es tan descriptiva como los nombres simples de variables.
Sin embargo, podría hacer:

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

Pero esas son 3 declaraciones más que prefiero evitar.

Solo busco una sintaxis de atajo. ¿Es posible?

Liberarse
fuente

Respuestas:

222

Lo primero que me viene a la mente:

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

la salida es, como era de esperar

1|2|3
Michael Krelin - hacker
fuente
4
¿Hay alguna forma de hacer que esto funcione si la primera variable contiene un espacio?
Rucent88
7
@Michael Using read -d "\n" v1 v2 <<<$(cmd)funciona perfectamente. ¡Gracias!
Rucent88
1
@LeeNetherton, buen punto, aunque no estoy seguro de si uno necesita el estado de retorno del comando echo :-) Creo que en el momento de escribir el bash de respuesta que admite esta sintaxis era menos común (como en la instalación predeterminada), aunque No estoy 100% seguro.
Michael Krelin - hacker
4
@ MichaelKrelin-hacker seguro, el estado de devolución de no echotiene sentido, pero estaba usando esta técnica para devolver varios valores de un script que me importaba el estado de devolución. Pensé en compartir mis hallazgos.
Lee Netherton
1
Por razones de seguridad se debe utilizar: read -r:do not allow backslashes to escape any characters
Tom Hale
18

Quería asignar los valores a una matriz. Entonces, extendiendo el enfoque de Michael Krelin , lo hice:

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

cuyos rendimientos:

2|4|6 

como se esperaba.

soundray
fuente
2
Para poner los valores en una matriz, ya existe una solución simple que mencioné en la pregunta:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
GetFree
Sí, lo había pasado por alto. Sin embargo, diría que mi sugerencia se adapta mejor a la asignación de matrices más grandes.
soundray
@soundray Su solución usa expansión y una cadena, siendo bash lo que es, dudo que funcione bien en ese escenario (pero no lo comprobé).
Camilo Martin
Por razones de seguridad se debe utilizar: read -r:do not allow backslashes to escape any characters
Tom Hale
5

Creo que esto podría ayudar ...

Para desglosar las fechas ingresadas por el usuario (mm / dd / aaaa) en mis scripts, almaceno el día, mes y año en una matriz, y luego coloco los valores en variables separadas de la siguiente manera:

DATE_ARRAY=(`echo $2 | sed -e 's/\// /g'`)
MONTH=(`echo ${DATE_ARRAY[0]}`)
DAY=(`echo ${DATE_ARRAY[1]}`)
YEAR=(`echo ${DATE_ARRAY[2]}`)
SDGuero
fuente
¿Por qué no evitar 4 subcapas más un proceso sed adicional, y hacer todo eso en una línea:IFS=/ read -r m d y < <(echo 12/29/2009)
Amit Naidu
5

A veces tienes que hacer algo raro. Supongamos que desea leer un comando (el ejemplo de fecha de SDGuero, por ejemplo) pero desea evitar múltiples bifurcaciones.

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

También podría ingresar al comando de lectura, pero luego tendría que usar las variables dentro de una subcapa:

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

resulta en ...

13 08 2013
n/a n/a n/a
Otheus
fuente
El readcomando no ocurre en una subcapa debido a las llaves, es porque tiene el comando de lectura en el lado derecho de la tubería. Debe ejecutar el readcomando en el shell actual, lo que puede hacer comoread day month year <<< `date "+%d %m %Y"`
neumática
No, read sucede, pero el alcance de las variables que lee queda fuera del alcance cuando finaliza la subcapa de la canalización.
Otheus
1
Mi comentario fue sobre la razón por la que la lectura ocurre en una subcapa, y ahora me doy cuenta de que leí mal lo que escribió. Pensé que querías decir que la subcapa se creó porque usaste las llaves alrededor de la declaración compuesta. ¡Pero! La razón por la que dio ese ejemplo fue para evitar la bifurcación, pero ¿no la bifurcación del subshell también?
neumática
El primer ejemplo requiere exactamente una bifurcación: para que bash pueda ejecutar el comando de fecha. En el segundo ejemplo, configura una canalización entre la fecha y su subconjunto. Creo que bash en estos días es lo suficientemente inteligente como para no meterse en el subshell, pero no estoy seguro de eso. En cualquier caso, parece que lo haría :)
Otheus
0

El capítulo 5 del Bash Cookbook de O'Reilly analiza (con cierta extensión) las razones del requisito en una asignación de variable de que no haya espacios alrededor del signo '='

MYVAR="something"

La explicación tiene algo que ver con distinguir entre el nombre de un comando y una variable (donde '=' puede ser un argumento válido).

Todo esto parece un poco como una justificación después del evento, pero en cualquier caso no se menciona un método de asignación a una lista de variables.

pavium
fuente
Sí, lo sé. Acabo de agregar espacios adicionales aquí y allá en aras de la legibilidad
GetFree
De hecho, esa es una motivación pobre: ​​¿y si ' ;' es un argumento válido? Cuando escribo ls ; cdtodavía llama lsy cdpese a los espacios. Si quiero enumerar los directorios llamados ;y cdpuedo escribir ls ';' cd.
PieterNuyts