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

zw963 · 2012年06月23日 · 最后由 wang0109 回复于 2012年06月24日 · 12329 次阅读

好久没发技术贴了, 在此分享给大家一个编写 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.

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

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

需要 登录 后方可回复, 如果你还没有账号请 注册新账号