Linux bash: присвоение множественных переменных

121

Существует ли в linux bash что-то похожее на следующий код в PHP:

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

т.е. вы присваиваете в одном предложении соответствующее значение трем различным переменным.

Скажем, у меня есть функция bash, myBashFuntionкоторая записывает в stdout строку «qwert asdfg zxcvb». Можно ли сделать что-то вроде:

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

Часть слева от знака равенства, конечно, недопустимый синтаксис. Я просто пытаюсь объяснить, о чем прошу.

Однако работает следующее:

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

Но индексированный массив не так нагляден, как простые имена переменных.
Однако я мог просто сделать:

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

Но это еще 3 утверждения, которых я бы предпочел избежать.

Я просто ищу сокращенный синтаксис. Является ли это возможным?

Получить бесплатно
источник

Ответы:

222

Первое, что приходит мне в голову:

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

вывод, что неудивительно

1|2|3
Михаил Крелин - хакер
источник
4
Есть ли способ заставить это работать, если первая переменная содержит пробел?
Rucent88 09
8
@Michael Using read -d "\n" v1 v2 <<<$(cmd)отлично работает. Спасибо!
Rucent88 09
1
@LeeNetherton, хороший момент, хотя я не уверен, нужен ли статус возврата команды echo :-) Я думаю, что на момент написания ответа bash, поддерживающий этот синтаксис, был менее распространен (как установлен по умолчанию), хотя я Я не уверен на 100%.
Михаил Крелин - хакер,
4
@ MichaelKrelin-hacker конечно, статус возврата echoбессмыслен, но я использовал эту технику, чтобы вернуть несколько значений из скрипта, который меня действительно заботил о статусе возврата. Думал поделиться своими выводами.
Ли Нетертон,
1
Для обеспечения безопасности следует использовать: read -r:do not allow backslashes to escape any characters
Том Хейл
18

Я хотел присвоить значения массиву. Итак, расширяя подход Майкла Крелина , я сделал:

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

что дает:

2|4|6 

как и ожидалось.

soundray
источник
2
Чтобы поместить значения в массив, уже существует простое решение, о котором я упоминал в вопросе:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
GetFree
Да, я этого не заметил. Я бы сказал, однако, что мое предложение лучше подходит для назначения массивов большего размера.
soundray
@soundray В вашем решении используется расширение и строка здесь, причем bash, я сомневаюсь, что он будет хорошо работать в этом сценарии (но я не проверял).
Камило Мартин
Для обеспечения безопасности следует использовать: read -r:do not allow backslashes to escape any characters
Том Хейл
5

Думаю, это может помочь ...

Чтобы разбить введенные пользователем даты (мм / дд / гггг) в моих сценариях, я сохраняю день, месяц и год в массиве, а затем помещаю значения в отдельные переменные следующим образом:

DATE_ARRAY=(`echo $2 | sed -e 's/\// /g'`)
MONTH=(`echo ${DATE_ARRAY[0]}`)
DAY=(`echo ${DATE_ARRAY[1]}`)
YEAR=(`echo ${DATE_ARRAY[2]}`)
SDGuero
источник
Почему бы не избежать 4 подоболочек плюс дополнительный процесс sed и просто сделать все это в одной строке:IFS=/ read -r m d y < <(echo 12/29/2009)
Амит Найду,
5

Иногда приходится делать что-нибудь фанковое. Предположим, вы хотите читать из команды (например, даты SDGuero, например), но вы хотите избежать множественных форков.

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

Вы также можете передать команду чтения, но тогда вам придется использовать переменные внутри подоболочки:

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

приводит к ...

13 08 2013
n/a n/a n/a
Otheus
источник
Команда readне выполняется в подоболочке из-за фигурных скобок, это потому, что у вас есть команда чтения в правой части канала. Вам нужно запустить readкоманду в текущей оболочке, что вы можете сделать какread day month year <<< `date "+%d %m %Y"`
пневматика
Нет - read происходит, но область переменных, в которые он считывает, выходит за пределы области действия, когда подоболочка конвейера заканчивается.
Otheus
1
Мой комментарий касался причины, по которой чтение происходит в подоболочке, и теперь я понимаю, что неправильно прочитал то, что вы написали. Я думал, вы имели в виду, что подоболочка была создана, потому что вы использовали фигурные скобки вокруг составного оператора. Но! Причина, по которой вы привели этот пример, заключалась в том, чтобы избежать разветвления, а не вилка подоболочки тоже?
пневматика
В первом примере требуется ровно одна вилка: чтобы bash мог запустить команду date. Во втором примере вы настраиваете конвейер между датой и вашей суб-оболочкой. Я думаю, что в наши дни bash достаточно умен, чтобы фактически не входить в подоболочку, но я не уверен в этом. Во всяком случае, похоже, что да :)
Отей
0

В главе 5 « Поваренной книги Bash» О'Рейли обсуждаются (довольно подробно) причины, по которым при присвоении переменной не должно быть пробелов вокруг знака «=».

MYVAR="something"

Объяснение как-то связано с различием между именем команды и переменной (где '=' может быть допустимым аргументом).

Все это выглядит как оправдание после события, но в любом случае нет упоминания о методе присвоения списку переменных.

pavium
источник
Да, я знаю. Я просто добавил лишние пробелы здесь и там для удобства чтения
GetFree
В самом деле, это плохая мотивация: что, если « ;» - верный аргумент? Когда я пишу ls ; cdэто до сих пор называет lsи , cdнесмотря на пробелы. Если я хочу , чтобы список каталогов , называемых ;и cdя могу только напечатать ls ';' cd.
PieterNuyts