访问bash命令行参数$ @ vs $ *


327

在许多SO问题和bash教程中,我看到我可以通过两种方式访问​​bash脚本中的命令行args:

$ ~ >cat testargs.sh 
#!/bin/bash

echo "you passed me" $*
echo "you passed me" $@

结果是:

$ ~> bash testargs.sh arg1 arg2
you passed me arg1 arg2
you passed me arg1 arg2

$*和之间有什么区别$@
一个人何时应使用前者,何时应使用后者?


看一下这个答案:stackoverflow.com/a/842325/671366
编码

IntelliJ中的静态分析被视为echo "something $@"错误
Alex Cohn,

Answers:


436

引用特殊参数时会出现差异。让我来说明差异:

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3

关于引号重要性的另一个示例:请注意,“ arg”和数字之间有2个空格,但是如果我不能引述$ word:

$ for word in "$@"; do echo $word; done
arg 1
arg 2
arg 3

在bash中,"$@"是要迭代的“默认”列表:

$ for word; do echo "$word"; done
arg  1
arg  2
arg  3

65
+1我一直认为最好通过一个简单的示例来最好地说明这个概念,在该示例中,bash手册完全缺乏。
chepner 2012年

5
有没有一种可能的使用情况,当$*"$*"可能需要,和目的不能送达$@"$@"
2013年

5
哪个版本更适合“包装器”脚本,其中脚本参数需要成为新命令的参数?
Segfault 2015年

7
在这种情况下,@ Segfault始终选择"$@"带引号。
glenn jackman

2
该答案包含有用的示例,但是如果它也解释了它们背后的机制,将会更好。为什么会这样工作?
Lii

255

Bash Hackers Wiki上的一个不错的概述表:

$ *与$ @表

其中c第三行是$IFS内部字段分隔符(shell变量)的第一个字符。

如果参数要存储在脚本变量中,并且参数应包含空格,我会全力建议采用一种"$*"将内部字段分隔符$IFS设置为tab技巧


42
...其中“ c”是$ IFS的第一个字符
glenn jackman

39
…… $IFS代表“内部场分离器”。
Serge Stroobandt,2015年

这是一个示例,其中包括带引号的输入。输入也很重要!
Serge Stroobandt

假设我要创建一个包装脚本,该脚本除了模仿包装命令的功能外什么也不做。我应该使用哪种语法将args从包装脚本传递到内部命令?
Marinos

44

$ *

从一个开始扩展到位置参数。当在双引号内进行扩展时,它将扩展为一个单词,每个参数的值由IFS特殊变量的第一个字符分隔。也就是说,“ $ *”等效于“ $ 1c $ 2c ...”,其中c是IFS变量值的第一个字符。如果未设置IFS,则参数之间用空格分隔。如果IFS为null,则参数连接时不插入分隔符。

$ @

从一个开始扩展到位置参数。当在双引号内进行扩展时,每个参数都会扩展为单独的单词。也就是说,“ $ @”等效于“ $ 1”“ $ 2” ...如果在单词中出现双引号扩展名,则第一个参数的扩展名将与原始单词的开头部分连接在一起,并且扩展名最后一个参数的后面与原始单词的最后一部分相连。当没有位置参数时,“ $ @”和$ @扩展为空(即,它们被删除)。

资料来源:Bash man



1

这个示例让我们可以突出显示在使用它们时“ at”和“ asterix”之间的区别。我宣布了两个数组“水果”和“蔬菜”

fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

printf "Fruits:\t%s\n" "${fruits[*]}"            
printf "Fruits:\t%s\n" "${fruits[@]}"            
echo + --------------------------------------------- +      
printf "Vegetables:\t%s\n" "${vegetables[*]}"    
printf "Vegetables:\t%s\n" "${vegetables[@]}"    

请参阅以下代码查看以下结果:

Fruits: apple pear plumm peach melon
Fruits: apple
Fruits: pear
Fruits: plumm
Fruits: peach
Fruits: melon
+ --------------------------------------------- +
Vegetables: carrot tomato cucumber potatoe onion
Vegetables: carrot
Vegetables: tomato
Vegetables: cucumber
Vegetables: potatoe
Vegetables: onion

6
从科学上讲,西红柿是水果。
兰迪

1
你有权利!“在植物学中,果实是开花后从卵巢形成的开花植物(也称为被子植物)中的种子结构。” en.wikipedia.org/wiki/
水果

@兰迪:从科学上讲,所有水果都是蔬菜(这是“植物”的代名词)。
Cris Luengo

@CrisLuengo异端!:)
兰迪
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.