1.4. 构建块

1.4.1. Shell 构建块

1.4.1.1. Shell 语法

如果输入没有被注释掉,shell 会读取它,并将其分解为单词和运算符,使用引用规则来定义输入的每个字符的含义。然后,这些单词和运算符会被转换成命令和其他构造,这些命令和构造会返回一个退出状态,可用于检查或处理。只有在 shell 以以下方式分析输入后,才会应用上述 fork-and-exec 方案

  • shell 从文件、字符串或用户的终端读取输入。

  • 输入被分解为单词和运算符,遵循引用规则,请参阅第 3 章。这些标记由元字符分隔。执行别名扩展。

  • shell解析(分析和替换)标记为简单和复合命令。

  • Bash 执行各种 shell 扩展,将扩展后的标记分解为文件名列表以及命令和参数。

  • 如果需要,执行重定向,从参数列表中删除重定向运算符及其操作数。

  • 命令被执行。

  • 可选地,shell 等待命令完成并收集其退出状态。

1.4.1.2. Shell 命令

一个简单的 shell 命令,例如 touch file1 file2 file3,由命令本身以及后面的参数组成,参数之间用空格分隔。

更复杂的 shell 命令由以各种方式排列在一起的简单命令组成:在管道中,一个命令的输出成为第二个命令的输入;在循环或条件构造中;或者在其他分组中。一些例子

ls | more

gunzipfile.tar.gz| tarxvf -

1.4.1.3. Shell 函数

Shell 函数是一种将命令分组以便稍后执行的方式,使用单个名称表示该组。它们的执行方式就像“常规”命令一样。当 shell 函数的名称用作简单命令名称时,将执行与该函数名称关联的命令列表。

Shell 函数在当前的 shell 上下文中执行;不会创建新进程来解释它们。

函数在第 11 章中解释。

1.4.1.4. Shell 参数

参数是存储值的实体。它可以是名称、数字或特殊值。对于 shell 的目的而言,变量是存储名称的参数。变量具有值和零个或多个属性。变量使用 declare shell 内建命令创建。

如果没有给出值,变量将被赋值为空字符串。变量只能使用 unset 内建命令删除。

变量赋值在第 3.2 节中讨论,变量的高级用法在第 10 章中讨论。

1.4.1.5. Shell 扩展

Shell 扩展在每个命令行被拆分为标记后执行。以下是执行的扩展

  • 花括号扩展

  • 波浪线扩展

  • 参数和变量扩展

  • 命令替换

  • 算术扩展

  • 单词拆分

  • 文件名扩展

我们将在第 3.4 节中详细讨论这些扩展类型。

1.4.1.6. 重定向

在执行命令之前,可以使用 shell 解释的特殊符号重定向其输入和输出。重定向也可以用于为当前 shell 执行环境打开和关闭文件。

1.4.1.7. 执行命令

在执行命令时,解析器标记为变量赋值(在命令名称之前)和重定向的单词会被保存以供稍后引用。未被标记为变量赋值或重定向的单词将被扩展;扩展后的第一个剩余单词被视为命令名称,其余单词是该命令的参数。然后执行重定向,然后扩展分配给变量的字符串。如果没有命令名称结果,变量将影响当前的 shell 环境。

shell 的重要任务之一是搜索命令。Bash 按如下方式执行此操作

  • 检查命令是否包含斜杠。如果不是,首先检查函数列表,看看它是否包含我们要查找的名称的命令。

  • 如果命令不是函数,则在内建列表中检查它。

  • 如果命令既不是函数也不是内建命令,则通过分析以下目录来查找它PATH。Bash 使用哈希表(内存中的数据存储区)来记住可执行文件的完整路径名,以便避免广泛的PATH搜索。

  • 如果搜索不成功,bash 会打印错误消息并返回退出状态 127。

  • 如果搜索成功,或者命令包含斜杠,shell 会在单独的执行环境中执行该命令。

  • 如果执行失败,因为该文件不可执行且不是目录,则假定它是一个 shell 脚本。

  • 如果命令不是异步启动的,shell 会等待命令完成并收集其退出状态。

1.4.1.8. Shell 脚本

当包含 shell 命令的文件在调用 Bash 时用作第一个非选项参数时(不带-c-s,这将创建一个非交互式 shell。此 shell 首先在当前目录中搜索脚本文件,然后在PATH如果找不到该文件,则在其中查找。