好久没发技术贴了,在此分享给大家一个编写 bash 脚本时,有关 $@ 和 $* 使用的小技巧。
因为一个小小的需求,最近编写了一个小脚本,真的很小,不过就这么小小的脚本,却总是抽风似的,在某些场景下会有问题。最终琢磨了一下午,才找到问题的源泉,也正是在这次实践中,才算真正的明白了$@
和$*
之间的不同,
概念:
$@
和$*
在 bash shell 下,表示某个命令的所有文件名参数
的集合,前者类似于 Ruby 之中的 ARGV[], 不过两者又不完全相同。
Trick:
$@和$*, 表示命令行下的某个命令的参数集合,在不使用""的情况下,它们是完全相同的。
如果某个命令以无参数的方式运行,则$@为空 (可以将$@
理解为这是一个数组), 而$永远不可能为空 (可以将``$``理解为一个字符串,可以是一个空串"", 不过空串作为命令参数被传递时,和不提供参数含义可是完全不一样的), 正因为这样一个简单的区别,如果传递$@或$*给另一个命令 (例如管道命令 grep), 最终表现可能会大相径庭,完全不同。
$@使用的更加普遍,而$*主要用在需要传递多个文件名参数
给其他命令的场合。
以一个实际示例来讲解,假设当前目录下有以下文件:
假设我有一个编辑器,叫做 e(且不管它是什么编辑器), 我希望实现以下功能:
e aa bb # => 打开文件 aa, bb. (如果文件名存在,则打开指定的文件名) e ccc # => 打开文件 ccc1 ccc2. (如果文件名不存在,则使用正则) e test_f # => 同上 e dd # => 如果文件名不存在,正则也为空,则新建文件。
shell 脚本的实现如下:
#!/bin/sh
case "$*" in
".")
command e .
;;
"")
command e
;;
*)
if [ -f "$*" -o -d "$*" ] &>/dev/null; then
echo "$*" |command xargs -n1 e
else
finded_file=$(command find -type f -maxdepth 1 |command egrep --color=auto -e "$*")
if [ "$finded_file" ]; then
echo $finded_file |command xargs -n1 e
else
# create or open file or multi-files.
echo "$*" |command xargs -n1 e
fi
fi
esac
以上代码,其中玄机在于command egrep --color=auto -e "$*"
, 此处必须使用$, 如果将其中的`$改为
$@`, 则会出错。
假设运行e aa bb
, 则
command egrep --color=auto -e "$*"
表示在之前的管道之中搜索 aa bb, 等价于 grep -e 'aa bb'
command egrep --color=auto -e "$*"
表示在文件 bb 内搜索内容 aa, 等价于:grep -e aa bb.
看到这里,明白$@和$*其中的奥妙了吧?上面的脚本,如果使用$@, 而且又碰巧,在 bb 的内容中包含 aa, 你就知道我为什么晕菜了...
p.s. 以上代码模板可以应用到任何经常使用的命令中去。例如:cd, cp.