bash如何以及为什么将“{xs [@]}”拆分为参数?

时间:2014-02-25 11:11:14

标签: bash

我基本了解bash如何将一行拆分为一个程序的参数,并且足以避免包含空格的参数出现问题,但我想更进一步,了解发生了什么以及为什么。大多数指南告诉你做了什么,但不知道为什么它有效。一些例子可能有助于解释......

我将使用这个简短的Python脚本来转储参数列表:

#!/usr/bin/env python
import sys
print sys.argv[1:]

我们称之为“dumpargs”。 (你可以用C语言写,甚至用bash写,但是Python很简洁,我不想通过与额外的bash解释和扩展字符串竞争来混淆问题。)

首先,一些简单的例子:

$ dumpargs foo bar baz
['foo', 'bar', 'baz']
$ dumpargs "foo bar" baz
['foo bar', 'baz']

好的,太好了。我们可以使用引号通过在其周围包装引号来传递包含空格的参数。但我们并不局限于在论证的外部引用引号。如果我们把它们放在中间怎么办?

$ dumpargs foo" "bar
['foo bar']
$ dumpargs foo" "bar" "baz xyzzy
['foo bar baz', 'xyzzy']

好的,很酷。我认为这表明引号只是修改了空格的解释方式。双引号之间出现的空格不是参数分隔符。未引用的空格成为分隔符,引用的空格成为真正的空格,引号蒸发。

阵列怎么样?

$ xs=(one two "buckle my shoe")

$ dumpargs ${xs[*]}
['one', 'two', 'buckle', 'my', 'shoe']
$ dumpargs ${xs[@]}
['one', 'two', 'buckle', 'my', 'shoe']
$ dumpargs "${xs[*]}"
['one two buckle my shoe']
$ dumpargs "${xs[@]}"
['one', 'two', 'buckle my shoe']

显然,四个中的最后一个通常是有用的,并且很可能是我们想要在我们的数组所代表的地方使用的,例如,文件名列表。其他都将"buckle my shoe"中的空格与数组元素之间的分隔符混淆。但它到底在做什么呢?看起来它由变量扩展和引用操作组成。是吗?或者bash只是在看到紧靠数组扩展的双引号时才使用特殊处理?

以下是一些尝试测试正在进行的测试的示例:

$ xs=(one two "buckle my shoe")

$ dumpargs "${xs[@]} stop"
['one', 'two', 'buckle my shoe stop']
$ dumpargs "${xs[@]} and ${xs[@]}"
['one', 'two', 'buckle my shoe and one', 'two', 'buckle my shoe']

我认为这至少表明它不仅仅是针对数组扩展的一对引号的特殊情况。数组扩展产生某种类似字符串的输出,并且引号会影响类似字符串的东西如何转换为参数序列。但它不仅仅是一个普通的字符串,因为它有两种截然不同的类似空间的东西。它有一些“参数分隔符”而不是引用成为参数分隔符,但它也有“诚实到善的空间”,如果它们被引号括起来就不会成为参数分隔符。相比之下,${xs[*]}输出一个只有“诚实到善的空间”的常规字符串,而没有特殊的“参数分隔符”。

这是理解它的好方法吗?有没有更好的方法来理解bash如何以及何时将数组呈现为一个字符序列以及它何时何地分裂参数?

1 个答案:

答案 0 :(得分:4)

此行为的起源可能是旧的“传递SUBhell参数”问题。在开始时,我们有$*,直到你开始在参数中使用空格。

 Input         Subshell sees
 a b           "a" "b"
 "a b"         "a" "b"
 a b\ c        "a" "b" "c" 
 a b\\\ c      "a" "b c" 

我们可以引用$*但是这会将所有参数合并为单个字符串参数(即子shell总是会看到"a b""a b c")。显然,这不好。

因此引入了@表单。如果没有引号,$*$@的行为相似。引号 - "$@" - 扩展为正确引用的参数列表。

当KSH / BASH引入数组时,它们保持对称(没有$*,你无法将数组转换成单个字符串)。

相关: