bash 中数组的长度到底是多少以及如何区分“*”和“@”?

bash 中数组的长度到底是多少以及如何区分“*”和“@”?

我有以下示例脚本,想知道数组的长度到底是多少,是字节、字符还是其他什么?

#!/bin/bash

# Arrays
# @ vs. *

ape=( "Apple Banana" "Emacs Window" "Panda Bamboo Nature" )
cape=( 'Ping Pong' 'King Kong' 'King Fisher Club' 'Blurb' )
jade=( ally belly cally delly )

echo Expansion with \*
echo ${ape[*]}
echo ${cape[*]}
echo -e "${jade[*]}\n"

echo Expansion with \@
echo ${ape[@]}
echo ${cape[*]}
echo -e "${jade[@]}\n"

echo Elements with \*
echo ${#ape[*]}
echo ${#cape[*]}
echo ${#jade[*]}

echo Elements with \@
echo ${#ape[@]}
echo ${#cape[@]}
echo ${#jade[*]}

echo -e "\nLength"
echo ${#ape}
echo ${#cape}
echo ${#jade}

从我知道的手册页来看,如果该词是否用双引号引起来,则数组扩展与 to 不同*,但我看不到任何差异。@为什么我在这两种情况下得到相同的结果?

输出如下:

Expansion with *
Apple Banana Emacs Window Panda Bamboo Nature
Ping Pong King Kong King Fisher Club Blurb
ally belly cally delly

Expansion with @
Apple Banana Emacs Window Panda Bamboo Nature
Ping Pong King Kong King Fisher Club Blurb
ally belly cally delly

Elements with *
3
4
4
Elements with @
3
4
4

Length
12
9
4

答案1

*您错过了它显示将数组扩展为单个字符串,并@扩展为单独引用的字符串的情况:

printf 'string "%s"\n' "${cape[*]}"

这会产生

string "Ping Pong King Kong King Fisher Club Blurb"

printf 'string "%s"\n' "${cape[@]}"

这会产生

string "Ping Pong"
string "King Kong"
string "King Fisher Club"
string "Blurb"

请记住,echo只是连接其参数并打印它们,而printf将使用参数填充其格式字符串,并在提供更多参数时重复相同的格式。

还,

for s in "${cape[*]}"; do
    echo "$s"
done

生成单行输出(它仅迭代单个字符串),而

for s in "${cape[@]}"; do
    echo "$s"
done

每个数组元素生成一个。


${array[*]}您总是希望在和扩展周围使用双引号${array[@]},除非您出于某种原因想要显式调用分词和文件名通配。您使用*or@取决于您是否需要将数组元素全部作为一个字符串,或者单独引用。

根据我的经验,很少使用[*].


当获取数组的长度时,使用哪个*或哪个并不重要。@但如果两者都不使用,您将获得数组第一个元素的字符长度。

答案2

根据您在变量赋值中使用的不同引用,我相信您将“如果该单词是否被双引号引起来”这句话误解为“如果数组元素被双引号引起来”,而手册意为“表示正在扩展的变量的单词是否用双引号引起来”。

您还可以使用echo同一行上发生的变量扩展;如果您使用更可配置的东西,您可能会得到更清晰的结果,例如printf善行南达做到了),或作为:

$ printf -- '->%s<-\n' "${ape[@]}"
->Apple Banana<-
->Emacs Window<-
->Panda Bamboo Nature<-

如果您可以看到 printf 所做的中间值,您会看到:

printf -- '->%s<-\n' "Apple Banana" "Emacs Window" "Panda Bamboo Nature"

与未引用的版本相反:

$ printf -- '->%s<-\n' ${ape[@]}
->Apple<-
->Banana<-
->Emacs<-
->Window<-
->Panda<-
->Bamboo<-
->Nature<-

...其中中间值为:

printf -- '->%s<-\n' Apple Banana Emacs Window Panda Bamboo Nature

...这准确地显示了元素已扩展的内容。在第一种情况下,变量被引用,因此不会发生进一步的分词,并且您会得到三个元素。在第二种情况下,这三个元素中的每一个也会经历分词,所以printf看到要打印的元素。

数组的“长度”通常是使用语法生成的元素数量${#ape[@]}。使用${#ape}bash 询问第一个元素的长度:

引用不带下标的数组变量相当于引用下标为 0 的数组变量

这就是为什么你会得到这些不同的值。

相关内容