将数组值作为用户输入读取会给出错误的数组长度,并且只有 -a 或 -p 在读取中起作用

将数组值作为用户输入读取会给出错误的数组长度,并且只有 -a 或 -p 在读取中起作用

问题1:我想在运行时获取数组项作为用户输入;打印项目并打印数组长度。这就是我所拥有的:

read -a myarray
echo "array items" ${myarray[@]}
echo "array length" ${#myarray[@]}

在运行时,我给出了以下内容作为输入,

$ ("apple fruit" "orange" "grapes")

输出是,

array items "apple fruit" "orange" "grapes"
array length 4

这是不正确的。

如果我不要求用户输入,而是使用作为代码一部分声明和初始化的数组,因为myarray=("apple fruit" "orange" "grapes")数组长度回显为 3。所以,看来我对 read 命令的使用不正确。

问题2:如果我在读取命令中添加提示,如下所示,

read -p "enter array items: " myarray

第一项“苹果水果”被打印为水果“并且长度也是错误的。

如果我删除提示并添加 -a,一切都很好。如果我将 a 和 p 结合起来并将其作为 read -ap 给出,则根本不会弹出提示。它等待值,但没有任何消息。为什么会这样呢?有人可以向我解释一下出了什么问题吗?

答案1

问题一:

在您的示例中,read不从命令行参数获取输入,而是从标准输入获取输入。因此,它接收到的输入不会经过bash的字符串解析器。相反,它被视为由空格分隔的文字字符串。因此,根据您的输入,您的数组值将变为:

[0]->("apple
[1]->fruit"
[2]->"orange"
[3]->"grapes"

要执行您想要的操作,您需要转义所有空格,以避免分隔符生效。也就是说,您必须在调用后输入以下输入read

apple\ fruit oranges grapes

问题 2:为了read将接收到的输入存储为数组,必须有一个-a开关,后跟数组名称。所以你需要:

read -a myarray -p "Enter your items"

答案2

shell 的命令行解析器关心双引号和单引号,但read并不关心(因此它也不会删除它们)。对于read输入,您需要反斜杠:

apple\ fruit orange grapes

答案3

如果您想让用户使用 shell 引用来分隔元素(而不仅仅是backslash),在 中zsh,您可以这样做:

IFS= read -r 'string?Please enter the elements: '
array=("${(@XQ)${(z)string}}")
  • (z)$string就是像 shell 解析器那样分割成元素。
  • Q从结果单词中删除一级引用
  • X报告语法中的错误消息
  • @并使用引号来保存空元素。

这样,用户可以输入以下内容:

'first word' "second word" third\ word $'word\nwith\nnewline' ''

请注意,虽然没有进行扩展,但预期的 shell 代码语法并不限于引用。例如,$(foo bar)将被解析为单个$(foo bar)单词,${unclosed会导致语法错误。用户需要将它们输入为'$(foo)' 'bar)', 或“${unknown”。

相关内容