Linux bash: 多个变量赋值

159

在linux bash中是否存在类似于PHP中以下代码的东西:

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

也就是说,你可以在一句话中给3个不同的变量分别赋值。

假设我有一个bash函数myBashFuntion,它将字符串"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]}

但这些语句我希望能够避免。

我只是在寻找一种简便的语法。这可行吗?

6个回答

288

我首先想到的是:

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

输出结果毫不意外

1|2|3

4
如果第一个变量包含空格,有没有办法让它起作用? - Rucent88
17
@Michael 使用read -d "\n" v1 v2 <<<$(cmd)非常完美。谢谢! - Rucent88
1
@LeeNetherton,说得好,不过我不确定是否需要echo命令的返回状态 :-) 我认为在回答时,支持这种语法的bash较少见(默认安装),但我不是100%确定。 - Michael Krelin - hacker
4
@MichaelKrelin-hacker,确实,echo命令的返回状态是无意义的,但我使用这种技巧来从一个我关心其返回状态的脚本中返回多个值。我想分享我的发现。 - Lee Netherton
2
为了安全起见,您应该使用:read -r不允许反斜杠转义任何字符 - Tom Hale
显示剩余6条评论

22

我想要将数值赋值给一个数组。所以,在扩展Michael Krelin的方法时,我执行了以下操作:

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

这将产生:

2|4|6 

如预期所料。


2
将值放入数组中已经有一个简单的解决方案,我在问题中提到过:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]} - GetFree
是的,我忽略了那个。不过,我认为我的建议更适合分配较大的数组。 - soundray
@soundray 您的解决方案使用了扩展和herestring,考虑到bash的特性,我怀疑它在那种情况下表现不佳(但我没有检查)。 - Camilo Martin
为了安全起见,您应该使用:read -r不允许反斜杠转义任何字符 - Tom Hale

5

我想这可能会有所帮助...

为了在我的脚本中分解用户输入的日期(mm/dd/yyyy),我将日、月和年存储到数组中,然后将这些值放入单独的变量中,如下所示:

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

4
为什么不避免4个子shell加上一个额外的sed进程,而只需在一行中完成所有操作:IFS=/ read -r m d y < <(echo 12/29/2009) - Amit Naidu

5
有时候你需要进行一些奇怪的操作。比如说,你想从命令行读取数据(像SDGuero的日期示例),但是你想要避免多个进程的产生。
read month day year << DATE_COMMAND
 $(date "+%m %d %Y")
DATE_COMMAND
echo $month $day $year

您也可以使用管道符号将命令输出传递到read命令中,但这样就必须在子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

导致...

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

read 命令不是因为花括号而在子 shell 中执行,而是因为你将 read 命令放在了管道的右侧。你需要在当前 shell 中运行 read 命令,可以使用以下命令:read day month year <<< \date "+%d %m %Y"`` - pneumatics
不会的,read确实发生了,但它读取的变量作用域会随着管道的子shell结束而消失。 - Otheus
1
我的评论是关于为什么读取发生在子shell中的原因,现在我意识到我误读了你写的内容。我以为你的意思是子shell是因为你在复合语句周围使用了花括号而创建的。但是!你给出这个例子的原因是为了避免分叉,但是子shell也会分叉,对吧? - pneumatics
第一个例子需要恰好一个fork:这样bash就可以启动日期命令。在第二个例子中,您在日期和子shell之间设置了一个管道。我认为现在的bash已经足够聪明,不会真正地分叉到子shell中,但我对此并不确定。无论如何,它看起来像是这样 :) - Otheus

0

O'Reilly 出版的 Bash Cookbook 第五章,详细讨论了变量赋值时必须在“=”符号周围没有空格的原因。

MYVAR="something"

这个解释与区分命令名称和变量名称有关(其中“=”可能是有效的参数)。

所有这些似乎都有点像事后辩解,但无论如何,没有提到一种将值赋给变量列表的方法。


是的,我知道。我只是为了可读性而在这里和那里添加了额外的空格。 - GetFree
确实,这是一个很差的动机:如果“;”是一个有效的参数怎么办?当我写ls; cd时,尽管有空格,它仍然调用lscd。如果我想列出名为“;”和“cd”的目录,我只需键入ls ';' cd即可。 - PieterNuyts

-2

让 var1=var2=var3=0
或者
var1=var2=var3="默认值"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接