shell 变量的扩展以及 glob 和 split 对其的影响

Gee*_*eek 21 shell shell-script terminology environment-variables quoting

这篇文章实际上包含两个单独的问题,但我认为将它们组合在一起会提供更多背景信息。我已经通过关于变量的引号解决这个问题,但我不太明白变量扩展的含义。所以我的第一个问题是:

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

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

  1. 球体
  2. 分裂

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

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

好像 echo $test 是 echo glob(split("$test"))。

我找不到直接解决的概念,任何答案通配符分裂,而是使用这些术语直接在回答其他问题,像这样的最近一个

Gil*_*il' 19

变量扩展(标准术语是参数扩展,有时也称为变量替换)基本上意味着用它的值替换变量。更准确地说,这意味着用从变量的值构建的其他文本替换$VARIABLE构造(或${VARIABLE}${VARIABLE#TEXT}或其他构造)。另一个文本是变量的扩展。

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

  1. 取变量的值,它是一个字符串。如果未定义变量,请使用空字符串。
  2. 如果构造包含转换,则应用它。例如,如果构造是${VARIABLE#TEXT},并且变量的值以 开头TEXTTEXT则从值的开头删除。
  3. 如果上下文需要单个单词(例如在双引号内,或在作业的右侧,或在此处的文档内),请停在此处。否则继续下一步。
  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*匹配任何文件,因此它被单独留下。结果是三个字符串的列表:bar, baz, c*

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

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

  • 请注意,它被称为 _p̲a̲r̲a̲m̲e̲t̲e̲r̲ expand_因为它适用于变量(`$var`)_和其他类型的参数,如`$1`、`$#`、`$?`、`$-`... (2认同)

slm*_*slm 12

全局/分裂

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

split("$test")会将“$test”的内容拆分为元素的“数组”。

glob(...)然后将照顾扩大任何包含壳的通配符,例如这些元件中的*或范围[1-2]

例子

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

$ test="afile[1-2] afile[3-5]"
Run Code Online (Sandbox Code Playgroud)

另外假设我们有一个目录,其中包含一些文件。

$ ls -1
afile1
afile2
afile3
afile4
afile5
Run Code Online (Sandbox Code Playgroud)

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

$ echo $test
afile1 afile2 afile3 afile4 afile5
Run Code Online (Sandbox Code Playgroud)

但是,如果我们在将变量作为参数传递给它时引用它,echo我们将获得原始文字字符串。

$ echo "$test"
afile[1-2] afile[3-5]
Run Code Online (Sandbox Code Playgroud)

变量扩展

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

在我们之前的例子中。当变量$test被提供给echo未引用的变量时,我们告诉 shell 继续将这些参数拆分,然后将它们全局化。

当它被引用时,我们基本上是用我们用双引号包裹的变量禁用了该功能。

例子

以下是通配和拆分的一些其他示例。

glob/splitting 自动发生

$ 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
Run Code Online (Sandbox Code Playgroud)

通过双引号禁用全局/拆分

$ 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}
Run Code Online (Sandbox Code Playgroud)