![x=( $@ ) 和 x="$@" 赋值的差异](https://linux22.com/image/207167/x%3D(%20%24%40%20)%20%E5%92%8C%20x%3D%22%24%40%22%20%E8%B5%8B%E5%80%BC%E7%9A%84%E5%B7%AE%E5%BC%82.png)
#!/bin/bash
if [ $# -gt 0 ]; then
snum=( $@ )
echo $snum
fi
./testscript.sh 1234 4568
当我运行像The output of echo command is only 这样的脚本时1234
,所以我想我没有构建所有位置参数的数组?
#!/bin/bash
if [ $# -gt 0 ]; then
snum="$@"
echo $snum
fi
并运行./testscript.sh 1234 4568
输出是1234 4568
我想知道为什么snum=( $@ )
只采用第一个位置参数?
答案1
在列表上下文中使用"$@"
(包括双引号)来获取的列表位置参数,单独引用。
在标量上下文中使用"$*"
(包括双引号)将位置参数连接到单个字符串以第一个字符$IFS
(通常是空格)作为分隔符。
使用$@
不带引号的(如第一个示例中所示)或"$@"
在标量上下文中使用(如第二个示例中所示)很少有意义。在bash
shell 中,在标量上下文中使用与将第一个字符设置为空格的情况"$@"
相同。"$*"
$IFS
使用时snum=( "$@" )
,您创建数组snum
。如果您访问变量为$snum
,您将获得数组的第一个元素。实际上,它与访问 相同${snum[0]}
。使用 为"${snum[@]}"
您提供单独引用的元素的列表,其方式与 类似"$@"
。使用"${snum[*]}"
给你相当于"$*"
, 但对于数组snum
。
假设您想snum
从位置参数列表创建一个数组 ,然后打印该数组(如果它不为空),您可以使用
#!/bin/bash
snum=( "$@" )
if [ "${#snum[@]}" -gt 0 ]; then
printf '%s\n' "${snum[@]}"
fi
snum
如果给脚本提供了参数,这将在单独的行上打印 的元素。
示例运行:
bash-5.1$ ./script 1 2 3 "hello world" 4
1
2
3
hello world
4
请注意,该hello world
参数被保留为单个参数,这将不是如果您忘记了周围的引号,情况就是这样$@
。
在单个字符串中打印位置参数列表,以冒号分隔。通过修改字符串在位置参数之间插入冒号$IFS
。
#!/bin/bash
IFS=:
snum="$*"
if [ -n "$snum" ]; then
printf '%s\n' "$snum"
fi
这里的区别在于snum
现在是单个字符串,而不是元素数组。如果该字符串非空,即如果为脚本提供了至少一个非空参数,则该脚本将输出该字符串。
或者,稍微修改我们的第一个示例以继续用作snum
数组,
#!/bin/bash
snum=( "$@" )
if [ "${#snum[@]}" -gt 0 ]; then
IFS=:
printf '%s\n' "${snum[*]}"
fi
示例运行:
bash-5.1$ ./script 1 2 3 "hello world" 4
1:2:3:hello world:4
答案2
var=( values )
是数组变量赋值
var=value
是标量变量赋值(并且var="$@"
,var
被分配位置参数与空间的串联,如下所示一字符串,因为它是标量)
$var
数组上的元素扩展为索引 0 的元素,与${var[0]}
您需要的数组中的所有元素相同${var[@]}
,这是从 Korn shell 复制的错误设计。
另请注意:
- split+glob 运算符在列表上下文中不加引号地保留参数扩展,您几乎永远不想这样做。具有讽刺意味的是,您在上面添加引号的唯一位置是不需要它们的地方。
echo
不能用于输出 中的任意数据bash
。
在这里,您想要:
#! /bin/bash -
print_space_separated() {
local IFS=' '
printf '%s\n' "$*"
}
if [ "$#" -gt 0 ]; then
snum=( "$@" )
print_space_separated "${snum[@]}"
fi
在who 的数组设计比 of 更zsh
接近的情况下,您可以这样做:csh
ksh
#! /bin/zsh -
if (( $# > 0 )) {
snum=( $argv )
print -r -- $snum
}
(其print -r
本身来自 ksh)
但需要注意的是,即使在该 shell 中的参数扩展时没有 split+glob,保留数组扩展不带引号仍然会删除空元素。要保留它们,您需要 ksh 语法:
#! /bin/zsh -
if (( $# > 0 )) {
snum=( "$@" )
print -r -- "${snum[@]}"
}
(尽管"${snum[@]}"
可以缩短为"$snum[@]"
)。
请注意, invar="$@"
或var="${array[@]}"
,var
最终包含一个由位置参数组成的字符串,该位置参数与$IFS
in的第一个字符连接zsh
,并与 的空格连接bash
。 POSIX 在那里未指定行为,$@
仅用于引用和列表上下文中。要获取与$IFS
可移植性的第一个字符连接的位置参数,请使用"$*"
(在列表或非列表上下文中)。
要将数组的元素与任意字符串(而不是 的第一个字符$IFS
)连接起来,请在:中使用j
参数扩展标志。没有同等的。有。zsh
${(j[that-string])array}
bash
fish
string join -- that-string $array