分享 [原创] Bash shell 下的 $@ 与 $* 的区别与用法, 附有趣的示例.

zw963 · June 23, 2012 · Last by wang0109 replied at June 24, 2012 · 13013 hits

好久没发技术贴了,在此分享给大家一个编写 bash 脚本时,有关 $@ 和 $* 使用的小技巧。

因为一个小小的需求,最近编写了一个小脚本,真的很小,不过就这么小小的脚本,却总是抽风似的,在某些场景下会有问题。最终琢磨了一下午,才找到问题的源泉,也正是在这次实践中,才算真正的明白了$@$*之间的不同,

概念: $@$*在 bash shell 下,表示某个命令的所有文件名参数的集合,前者类似于 Ruby 之中的 ARGV[], 不过两者又不完全相同。

Trick:

  • $@和$*, 表示命令行下的某个命令的参数集合,在不使用""的情况下,它们是完全相同的。

  • 如果某个命令以无参数的方式运行,则$@为空 (可以将$@理解为这是一个数组), 而$永远不可能为空 (可以将``$``理解为一个字符串,可以是一个空串"", 不过空串作为命令参数被传递时,和不提供参数含义可是完全不一样的), 正因为这样一个简单的区别,如果传递$@或$*给另一个命令 (例如管道命令 grep), 最终表现可能会大相径庭,完全不同。

  • $@使用的更加普遍,而$*主要用在需要传递多个文件名参数给其他命令的场合。

以一个实际示例来讲解,假设当前目录下有以下文件:

  • aa
  • bb
  • ccc1
  • ccc2
  • 20120623_a_test_file.rb

假设我有一个编辑器,叫做 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.

只用过$@,学习啦,多谢分享

粗俗点说,$@ 是分开的字串, $* 是一个字串。

You need to Sign in before reply, if you don't have an account, please Sign up first.