ChatGPT解决这个技术问题 Extra ChatGPT

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]}

但这些是我宁愿避免的另外 3 个陈述。

我只是在寻找一种快捷语法。可能吗?


T
Tom Hale

我首先想到的是:

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

不出所料,输出是

1|2|3

如果第一个变量包含空格,是否有办法让它工作?
@Michael 使用 read -d "\n" v1 v2 <<<$(cmd) 效果很好。谢谢!
@LeeNetherton,好点,虽然我不确定是否需要 echo 命令的返回状态:-) 我认为在编写答案时支持这种语法的 bash 不太常见(如默认安装),虽然我我不是 100% 确定的。
@MichaelKrelin-hacker 当然,echo 的返回状态毫无意义,但我正在使用这种技术从我确实关心返回状态的脚本中返回多个值。我想我会分享我的发现。
为了安全起见,您应该使用:read -rdo not allow backslashes to escape any characters
J
John Strood

我想将值分配给一个数组。所以,扩展 Michael Krelin's approach,我做了:

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

产生:

2|4|6 

正如预期的那样。


要将值放入数组中,我已经在问题中提到了一个简单的解决方案:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
是的,我忽略了这一点。不过,我会争辩说,我的建议更适合分配更大的数组。
@soundray您的解决方案使用扩展和herestring,bash就是我怀疑它在那种情况下会表现良好(但我没有检查)。
为了安全起见,您应该使用:read -rdo not allow backslashes to escape any characters
S
SDGuero

我认为这可能会有所帮助...

为了在我的脚本中分解用户输入的日期(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 个子外壳加上一个额外的 sed 进程,而只需在一行中完成所有这些:IFS=/ read -r m d y < <(echo 12/29/2009)
O
Otheus

有时你必须做一些时髦的事情。假设您想从命令中读取数据(例如 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 中,这是因为您在管道的右侧有读取命令。您需要在当前 shell 中运行 read 命令,您可以像 read day month year <<< `date "+%d %m %Y"` 一样执行此操作
否 - read 发生,但当管道的子外壳结束时,它读取的变量范围超出范围。
我的评论是关于读取发生在子外壳中的原因,我现在意识到我误读了您写的内容。我以为您的意思是创建了子shell,因为您在复合语句周围使用了花括号。但!您给出该示例的原因是为了避免分叉,但 subshell 也不会分叉吗?
第一个示例只需要一个 fork: 以便 bash 可以启动 date 命令。在第二个示例中,您在日期和子 shell 之间设置了一个管道。我认为这些天 bash 足够聪明,不会真正分叉到子外壳中,但我不确定这一点。无论如何,它看起来会:)
p
pavium

O'Reilly 的 Bash Cookbook 的第 5 章(在一定程度上)讨论了变量赋值中要求“=”符号周围没有空格的原因

MYVAR="something"

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

这一切似乎有点像事后证明,但无论如何都没有提到分配给变量列表的方法。


是的,我知道。为了便于阅读,我只是在这里和那里添加了额外的空格
事实上,这是一个糟糕的动机:如果“;”是一个有效的论点怎么办?当我写 ls ; cd 它仍然调用 lscd 尽管有空格。如果我想列出名为 ;cd 的目录,我只需键入 ls ';' cd
A
Alexander Campos

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