除非特别说明,本文中出现的 Shell 均指 Bash 4.3。首先说一个基础知识:Shell 中的变量在展开成值(Parameter Expansion)之后,这个值在某些上下文(Context)中,还会进行分词操作(Word Splitting),但在另外一些上下文中,不会进行分词操作。本文中把会进行分词操作的上下文叫做列表上下文(List Context),把不会进行分词的上下文叫做标量上下文(Scalar Context)。还有一个基础知识再提一嘴,就是 Shell 在分词时会跳过那些被双引号包围的词。

因为 $* 和 $@ 这两个特殊变量在以上两种上下文中的展开结果不一样,所以下面必须分两种情况讨论。

列表上下文

列表上下文是我们最熟悉的情况,比如在简单命令的参数中,又比如在 for-in 语句的参数中,这些地方需要的都是多个词,所以 Shell 规定在这些地方要进行分词操作。

$*

$* 在列表上下文中会展开成 $1 $2 $3 ... 多个词,而又因列表上下文存在分词操作,所以 $1 $2 等等都会再被 IFS 分割。

$ set a "b c" d

$ printf "%s\n" $* # $2 的值为 "b c",但由于 $2 本身没有被双引号包围,所以会被分成两个词 b c,所以一共就成了 a b c d 四个参数

a

b

c

d

"$*"

"$*" 在列表上下文中会展开成 "$1c$2c$3...",c 是 IFS 的第一个字符,如果 IFS 为空,则 c 也是空,如果 IFS 不存在,则 c 为空格,虽然这里存在分词操作,但由于展开后的值仍处于双引号中,所以分词操作不会有任何效果。

$ set a "b c" d

$ IFS=:

$ printf "%s\n" "$*" # 所有位置参数连接成了一个参数

a:b c:d

$@

$@ 在列表上下文中的表现和 $* 在列表上下文中的表现完全一样。

$ set a "b c" d

$ printf "%s\n" $@

a

b

c

d

"$@"

"$@" 在列表上下文中会展开成 "$1" "$2" "$3" ...,由于展开后的每个值都处于双引号中,所以分词操作不会有任何效果。

$ set a "b c" d

$ printf "%s\n" "$@"

a

b c

d

列表上下文是我们最熟悉的,Bash manual 对 $* 和 $@ 的讲解也仅限于列表上下文中的表现,下面我们讲讲它们俩在标量上下文中的表现。

标量上下文

最常见的标量上下文就是赋值语句的右边,此外还有 case 关键字的后面,以及 [[ ]] 之间等等,这些地方需要的都是一个词,所以 Shell 规定在这些地方不进行分词操作。

$*

$* 在标量上下文中展开成 $1c$2c$3...,c 是 IFS 的第一个字符,由于标量上下文没有分词操作,所以这就结束了,也就是说,$* 在标量上下文的效果等同于 "$*" 在列表上下文中的效果。

$ set a "b c" d

$ IFS=:

$ var=$* # var 的值成了 "a:b c:d"

$ echo "$var"

a:b c:d

"$*"

"$*" 在标量上下文中展开成 "$1c$2c$3...",由于反正没有分词操作,所以和 $* 在标量上下文中的表现一样。所以也就是说 var=$* 和 var="$*" 完全一样。

$@

$@ 在标量上下文展开成 $1空格$2空格$3...,这里用“空格”字样是为了说明展开后的值是一个词。也就是说,$@ 和 $* 在标量上下文下的区别仅仅是前者用空格做分隔符后者用 IFS 的第一个字符做分隔符这一个区别。

$ set a "b c" d

$ IFS=:

$ var=$* # var 的值成了 "a b c d",不使用 IFS

$ echo "$var"

a b c d

"$@"

"$@" 在标量上下文中展开成 "$1空格$2空格$3..." 和不加引号效果一样,var=$@ 等效于 var="$@"。

再总结一下就是,在标量上下文中,$* 和 $@ 加不加引号都一样,它俩的区别就是分隔符的区别,它俩展开后的结果都是用一个分隔符把所有位置参数连接成了一个词。下面再用 [[ ]] 的代码示例巩固一下它俩的区别:

$ set a "b c" d

$ IFS=:

$ [[ "$*" == "a:b c:d" ]]; echo $?

0

$ [[ "$@" == "a b c d" ]]; echo $?

0

在实际编码中没必要记忆这些区别,你只需要记住一点,需要多个词的时候用 "$@",需要一个词的时候用 "$*",是的,永远带着引号。此外,由于 Posix 规范明确规定了“本规范不对 $@ 在标量上下文上的表现做任何定义”,所以上面的一些代码示例在 Bash 以外的 Shell 上可能有不同的结果。

最后一句,$* 和 $@ 的所有表现都应该能推广到带 * 和 @ 下标的任意数组上。

再谈 $* 和 $@ 在 Bash 中的表现的更多相关文章

  1. 『忘了再学』Shell基础 — 9、Bash中的特殊符号(一)

    目录 1.双单引号 2.双引号 3.$符号 4.反引号 5.$()符号 6.#符号 7.\符号 1.双单引号 '':单引号.在单引号中所有的特殊符号,如$和"`"(反引号)都没有特 ...

  2. 『忘了再学』Shell基础 — 10、Bash中的特殊符号(二)

    提示:本篇文章接上一篇文章,主要说说()小括号和{}大括号的区别与使用. 8.()小括号 ():用于一串命令执行时,()中的命令会在子Shell中运行.(和下面大括号一起说明) 9.{}大括号 {}: ...

  3. Bash中的任务(job)管理

    本来不准备写这篇博客的,因为任务管理(job管理)非常非常常用,以至于觉得根本没有必要去写这样一个东西.但想了下,还是记录一下吧,也许有人会用到呢. 不知你是否碰到过这样的情况,当你兴致勃勃的打开VI ...

  4. bash中的数值运算

    第一种,使用((表达式)): a=3 ((b=a+2)) echo $b 第二种使用let: let "c=$a+4" echo $c 第三种,使用expr表达式(注意空格不能少) ...

  5. echo $[1 + 2] shell中 $[] 在bash中同$(()),用于算术计算

    shell脚本编写:echo $[ 11#8+1] 输出结果是几,为什么,怎么算来的?  摘自:https://zhidao.baidu.com/question/334766451.html   结 ...

  6. bash中前后移动一个单词和删除单词的快捷键

    bash中一个很重要的快捷键,就是向后删除一个单词: ctrl+w=ctrl+W 一个字符一个字符的移动是: ctrl+f, ctrl+b 但是, 一个单词一个单词的移动是: (但是, 这个用得比较少 ...

  7. Bash 中的 $0 在什么时候不是 argv[0]

    每个 C 程序都有一个 main 函数,每个 main 函数都有一个 argv 参数,这个参数是一个字符串数组,这个数组的值是由该 C 程序的父进程在通过 exec* 函数启动它时指定的. 很多人说 ...

  8. ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法

    ORACLE 查询一个数据表后通过遍历再插入另一个表中的两种写法 语法 第一种: 通过使用Oracle语句块  --指定文档所有部门都能查看 declare cursor TABLE_DEPT and ...

  9. bash中不可以用字符串做数组下标

    bash中可以用字符串做数组下标吗例如 test["abc"]=1------解决方案-------------------- 好像是误会,是awk里可以,bash shell里不 ...

随机推荐

  1. (转)CNBLOG离线Blog发布方法

    原文章路径:http://www.cnblogs.com/liuxianan/archive/2013/04/13/3018732.html (新添了插件路径) 去年就知道有这个功能,不过没去深究总结 ...

  2. grub2挂在iso镜像“ /dev/disk/by-label/XXXX error: boot device didn't show up after 30 seconds”问题

    两种解决办法: 方法A: mkdir /cdrom mount -t vfat /dev/sda1 /cdrom modprobe loop losetup /dev/loop6 /cdrom/boo ...

  3. [转]jQuery的each方法的几种常用的用法

    下面提一下jQuery的each方法的几种常用的用法 复制代码 代码如下:  var arr = [ "one", "two", "three&quo ...

  4. httpclient进行basic auth认证

    private HttpClientContext context = HttpClientContext.create(); public void addUserOAuth(String user ...

  5. 《Invert》开发日志00:缘起

    按照所有程序员的惯例,编号从0开始.本系列日志将记录一款独立游戏 发起->构思->设计->实现->完善->测试(如果需要)->上线->后期维护(如果有人玩) ...

  6. bzoj-4514(网络流)

    题目链接: 4514: [Sdoi2016]数字配对 Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数 ...

  7. IntelliJ IDEA设置JVM运行参数

    2015十一月 28 原 IntelliJ IDEA设置JVM运行参数 分类:JavaSE (11566) (1) 打开 IDEA 安装目录,看到有一个 bin 目录,其中有两个 vmoptions ...

  8. PhpStorm XDebug 远程调试

    现在我们自己公司的各种开发和测试服务器,都是使用阿里云的服务器.一些PHP的项目,无法在本地搭建完整的环境,在外网服务器上调试更方便定位问题.发现网上没有完整的关于如何配置PHPStorm和XDebu ...

  9. input 禁止输入法

    <INPUT TYPE = text STYLE = "ime-mode:disabled" > 即可禁止输入法 js形式: active 代表输入法为中文inacti ...

  10. Learning to rank 介绍

    PS:文章主要转载自CSDN大神hguisu的文章"机器学习排序":          http://blog.csdn.net/hguisu/article/details/79 ...