`$@` 与 `$*` 行为

`$@` 与 `$*` 行为

bash手册说:

关于:$*

当扩展发生在双引号内时,它会扩展为单个单词,每个参数的值由IFS特殊变量的第一个字符分隔。即,"$*"相当于"$1c$2c...",其中c是变量值的第一个字符IFS

关于:$@

当扩展发生在双引号内时,每个参数都会扩展为一个单独的单词。即,"$@"相当于"$1" "$2" ...

IFS提供变量值的第一个字符事实上,在一个空间中,我似乎无法想出一个例子来说明这两个特殊参数会产生不同的行为。任何人都可以给我提供一个例子(再次,不改变IFS),他们会产生不同的行为?

我自己的测试,仍然让我有点困惑,如下:

#!/usr/bin/env bash
# File: test.sh
# set foo and bar in the global environment to $@ and $*

test_expansion () {
  foo="$@"
  bar="$*"
}

现在测试:

. test.sh
test_expansion a b c d
# foo is $@
# bar is $*

for e in "$foo"; do
  echo "$e"
done
# a b c d

for e in "$bar"; do
  echo "$e"
done
# a b c d

答案1

当您在命令行中传递的参数包含 IFS 字符时(例如带有空格的参数),就会出现差异。要查看差异,请查看此脚本:

#!/bin/bash

echo 'Here is $*'
for x in "$*"; do
    echo "  !${x}!"
done

echo ""
echo 'And here is $@'
for x in "$@"; do
    echo "  !${x}!"
done

exit 0

现在,看看当您传递带有空格的参数时的区别。

./testspace01.sh "This is" a test
Here is $*
  !This is a test!

And here is $@
  !This is!
  !a!
  !test!

更新啊,将命令行中传递的内容分配给变量会带来自己的小怪癖。 :)

请记住,命令行中传入的所有内容都是一个数组。因此,将数组分配给字符串与对数组进行签名不同。并且,处理数组的方式有所不同,具体取决于您使用的是星号还是星号。这是我的脚本的更新版本。

#!/bin/bash

s_star="$*"
echo 'Here is s_star'
for x in "${s_star}"; do
    echo "  !${x}!"
done

a_star=("$*")
echo ""
echo 'Here is a_star'
for x in "${a_star}"; do
    echo "  !${x}!"
done

s_at="$@"
echo ""
echo 'Here is s_at'
for x in "${s_at}"; do
    echo "  !${x}!"
done

a_at=("$@")
echo ""
echo 'Here is a_at (using star)'
for x in "${a_at[*]}"; do
    echo "  !${x}!"
done

echo ""
echo 'Here is a_at (using at)'
for x in "${a_at[@]}"; do
    echo "  !${x}!"
done

exit 0

这是输出:

./testspace02.sh "This is" a test
Here is s_star
  !This is a test!

Here is a_star
  !This is a test!

Here is s_at
  !This is a test!

Here is a_at (using star)
  !This is a test!

Here is a_at (using at)
  !This is!
  !a!
  !test!

正如您所看到的,有不同的行为。

答案2

尝试这个:

#!/bin/bash
show-difference () {
    for e in "$@" ; do
        printf '<%s>\n' "$e"
    done
    for e in "$*" ; do
        printf '[%s]\n' "$e"
    done
}

show-difference {a..h}

输出:

<a>
<b>
<c>
<d>
<e>
<f>
<g>
<h>
[a b c d e f g h]

"$*"是单个单词,而"$@"将所有参数扩展为单个单词。此外,"$@"即使参数包含 IFS 的第一个字符,也能正常工作。

答案3

set -- "hello there" bumblebee

printf '%s\n' "$@"
printf '%s\n' "$*"

结果:

hello there
bumblebee

其次是

hello there bumblebee

这表明"$@"生成一个列表单独引用的元素,同时"$*"生成单个引用的字符串。

使用bash,这也可以通过一个简短的 shell 脚本来说明,该脚本采用多个命令行参数:

#!/bin/bash

IFS='_'

atarray=( "$@" )
stararray=( "$*" )

printf 'at: %s\n' "${atarray[@]}"
printf 'star: %s\n' "${stararray[@]}"

运行它:

$ bash ./script.sh "one two" three four
at: one two
at: three
at: four
star: one two_three_four

这也表明 using"$*"将使用 in 中的值$IFS(仅第一个字符)来分隔扩展产生的字符串中的元素。

相关内容