shell变量的扩展以及glob的影响和拆分


18

这篇文章实际上包含两个独立的问题,但我认为将它们组合在一起将提供更多的上下文。我已经在变量引号上讨论这个问题,但我不太了解变量扩展首先是什么意思。所以我的第一个问题是:

  1. 在unix / linux中,变量扩展是什么?

我的问题的第二部分涉及以下术语:

  1. 球状
  2. 分裂

以上是什么意思,它们如何影响变量扩展?原始问题的答案提到以下内容:

将没有引号(在列表上下文中)视为split + glob运算符。

好像echo $ test是echo glob(split(“ $ test”))一样。

我找不到任何直接解决“ 遍历分裂 ”概念的答案,而是直接将这些术语用于回答其他问题,例如最近的问题。


Answers:


15

变量扩展(标准术语是参数扩展,有时也称为变量替换)基本上意味着用其值替换变量。更确切地说,它是指取代$VARIABLE构建体(或${VARIABLE}${VARIABLE#TEXT}通过从所述变量的值建立某些其他文本或其他构建体)。这另一文本是变量的扩展。

扩展过程如下。(我只讨论常见的情况,一些shell设置和扩展会修改行为。)

  1. 取变量的值,它是一个字符串。如果未定义变量,请使用空字符串。
  2. 如果构造包含转换,请应用它。例如,如果构造为${VARIABLE#TEXT},并且变量的值以开头TEXTTEXT则从值的开头删除。
  3. 如果上下文需要一个单词(例如,双引号中,作业的右侧或here文档中),请在此处停止。否则,请继续下一步。
  4. 在每个空白序列处将值拆分为单独的单词。(IFS可以将变量更改为在空格以外的字符处分割。)因此,结果不再是字符串,而是字符串列表。如果该值仅包含空格,则此列表可以为空。
  5. 将列表的每个元素都视为文件名通配符模式,即glob。如果该模式与某些文件匹配,则将其替换为匹配文件名的列表,否则将不予处理。

例如,假设变量foo包含a* b* c*与当前目录中包含的文件barbazpaz。然后${foo#??}扩展如下:

  1. 变量的值是8个字符的字符串a* b* c*
  2. #??表示去除前两个字符,得到6个字符的字符串 b* c*(带有初始空格)。
  3. 如果扩展是在列表上下文中(即不在双引号或其他类似上下文中),请继续。
  4. 将字符串拆分为以空格分隔的单词,从而产生两个字符串的列表:b*c*
  5. b*解释为模式的字符串与两个文件匹配:barbaz。该字符串不c*匹配任何文件,因此将其保留下来。其结果是三个字符串的列表:barbazc*

例如echo ${foo#??}打印bar baz c*(命令echo将其参数连接在一起,中间有一个空格)。

有关更多详细信息,请参见:


2
请注意,这就是所谓的参数扩展,因为它适用于变量($var其他类型的参数一样$1$#$?$-...
斯特凡Chazelas

12

全局/拆分

我先处理glob / split。您链接到@Stephane的答案是在一般意义上使用这些术语。它们不是实际的命令或类似的东西,只是伪操作。

split("$test")将“$测试”向上的内容分割成一个元件的“阵列”。

然后,glob(...)它将注意扩展其中包含诸如*或范围之类的shell球形字符的任何这些元素[1-2]

说我们的字符串$test如下。

$ test="afile[1-2] afile[3-5]"

还可以说我们有一个包含一些文件的目录。

$ ls -1
afile1
afile2
afile3
afile4
afile5

现在,如果我们尝试在不带引号的情况下回显它,您应该注意到我们的字符串在空格处分开,然后所有的通配符都会扩展。

$ echo $test
afile1 afile2 afile3 afile4 afile5

但是,如果我们在将变量作为参数传递时引用该变量,则会echo得到原始的文字字符串。

$ echo "$test"
afile[1-2] afile[3-5]

可变膨胀

术语变量扩展旨在涵盖Shell作为其基本操作的一部分执行的基本操作。Shell负责解析输入,然后在语法上认为正确之后执行该输入。

在我们之前的示例中。当变量$test被提供给echo未加引号的时候,我们告诉外壳程序继续进行操作,将这些参数拆分开,然后将它们放宽。

用引号括起来时,我们实际上是在用双引号包裹的变量禁用了该功能。

这是一些其他的globbing和split示例。

球/分裂自动发生

$ echo file{1..3}
file1 file2 file3

$ echo file{1..3} dir{a..b}
file1 file2 file3 dira dirb

$ echo dir{z..w} file{A..D}
dirz diry dirx dirw fileA fileB fileC fileD

$ echo dir{z..w} file{A..B} fileC
dirz diry dirx dirw fileA fileB fileC

通过双引号禁用glob /拆分

$ echo "dir{z..w} file{A..B} fileC"
dir{z..w} file{A..B} fileC

$ echo "dir{z..w} file{A..B}"
dir{z..w} file{A..B}

我不知道范围也按相反的顺序工作。
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.