关于Bash中$、@、*扩展行为及$特性的技术咨询
搞懂Bash中$扩展的那些“迷惑行为”
咱们一个个拆解你遇到的现象,核心要先记住:Bash里没定义过的变量,展开后就是空字符串,大部分你觉得奇怪的表现都源于这个规则。
一、$*和$@*的差异解析
默认你当前目录已经有foo、bar、zoo这三个文件哈,不然ls也列不出来。看这两个命令:
echo $*:$*是用来指代脚本/函数接收的所有位置参数的,你现在是在交互式Shell里直接敲命令,根本没传任何位置参数,所以$*展开后就是空,echo空内容自然啥也不输出。echo $@*:这里要拆成两部分看——$@同样是位置参数(和$*的差异在多参数引号处理,但这里没参数,所以也是空),后面跟着的*是文件名通配符(路径名扩展)。当$@展开为空后,整个命令就变成了echo *,而*会匹配当前目录下所有非隐藏文件,也就是foo bar zoo,所以你就看到这个输出了。说白了,$@*其实是“空+通配符”,等价于直接用*。
二、那些$开头命令的诡异表现
再逐个看你遇到的情况:
ls $:单独的$不是合法的变量引用格式——变量引用得是$varname或者${varname}这种,变量名得是字母/下划线开头、包含字母数字下划线的。所以Bash不会把这个$当作变量,而是直接把它当成一个文件名传给ls,你目录里没有叫$的文件,自然就报错了。ls $*:还是回到位置参数,$*在交互式Shell里是空,所以这个命令等价于ls(不带任何参数),而ls默认就是列出当前目录的所有文件,所以就输出了foo bar zoo。ls $a(或任意字符):$a是你没定义过的变量,按照规则展开为空字符串,命令就变成了ls,同样触发默认的列当前目录操作,所以输出结果和上面一样。
额外补充:验证逻辑的小实验
你可以试试这几个操作加深理解:
- 先定义变量
a=test,再执行ls $a,就会发现它去查找名为test的文件,而非列当前目录。 - 执行
set -u(开启“引用未定义变量报错”模式),再敲echo $a,就会直接报错,而不是展开为空。 - 写个小脚本
test.sh:echo $*,然后执行./test.sh hello world,就能看到$*输出hello world,这才是位置参数的正确用法场景。
内容的提问来源于stack exchange,提问作者Wizard
相关产品推荐
相关产品推荐

