x=( $@ ) 和 x="$@" 赋值的差异

x=( $@ ) 和 x="$@" 赋值的差异
#!/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(通常是空格)作为分隔符。

使用$@不带引号的(如第一个示例中所示)或"$@"在标量上下文中使用(如第二个示例中所示)很少有意义。在bashshell 中,在标量上下文中使用与将第一个字符设置为空格的情况"$@"相同。"$*"$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接近的情况下,您可以这样做:cshksh

#! /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最终包含一个由位置参数组成的字符串,该位置参数与$IFSin的第一个字符连接zsh,并与 的空格连接bash。 POSIX 在那里未指定行为,$@仅用于引用和列表上下文中。要获取与$IFS可移植性的第一个字符连接的位置参数,请使用"$*"(在列表或非列表上下文中)。

要将数组的元素与任意字符串(而不是 的第一个字符$IFS)连接起来,请在:中使用j参数扩展标志。没有同等的。有。zsh${(j[that-string])array}bashfishstring join -- that-string $array

相关内容