![`$@` 与 `$*` 行为](https://linux22.com/image/142681/%60%24%40%60%20%E4%B8%8E%20%60%24*%60%20%E8%A1%8C%E4%B8%BA.png)
这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
(仅第一个字符)来分隔扩展产生的字符串中的元素。