第二十四章:写你的第一个脚本

在前面的章节中,我们组装了一系列命令行工具。虽然这些工具可以解决多种计算问题,但我们仍然局限于在命令行上逐一手动使用它们。如果我们能让shell做更多的工作,那岂不是很棒?我们可以。通过将我们的工具连接到我们自己设计的程序中,shell可以自己执行复杂的任务序列。我们可以通过编写 shell scripts 来实现这一点。

第二十四章:写你的第一个脚本什么是shell脚本如何编写shell脚本脚本文件格式可执行权限脚本文件位置脚本的好位置更多格式化技巧长选项名缩进和行延续配置vim进行脚本编写总结

什么是shell脚本

简而言之,shell脚本是一个包含一系列命令的文件。shell读取此文件并执行命令,就像它们是直接在命令行上输入的一样。

shell有点独特,因为它既是系统的强大命令行界面,也是脚本语言解释器。正如我们将看到的,大多数可以在命令行上完成的事情都可以在脚本中完成,而大多数在脚本中可以完成的事情也可以在命令行将完成。

我们已经介绍了许多shell功能,但我们关注的是那些最常直接在命令行上使用的功能。shell还提供了一组通常(但并非总是)在编写程序时使用的功能。

如何编写shell脚本

要成功创建和运行shell脚本,我们需要做三件事。

  1. 写一个脚本。

    Shell脚本是普通的文本文件。因此,我们需要一个文本编辑器来编写它们。最好的文本编辑器将提供语法高亮显示(syntax highlighting),使我们能够看到脚本元素的颜色编码视图。语法高亮显示将帮助我们发现某些常见错误。 vimgeditkate 和许多其他编辑器都是编写脚本的好选择。

  2. 使脚本可执行。

    系统非常挑剔,不允许将任何旧文本文件视为程序,这是有充分理由的!我们需要设置脚本文件的权限以允许执行。

  3. 把脚本放在shell可以找到的地方。

    当没有指定明确的路径名时,shell会自动在某些目录中搜索可执行文件。为了最大限度的方便,我们将把脚本放在这些目录中。

脚本文件格式

按照编程传统,我们将创建一个“Hello World”程序来演示一个极其简单的脚本。让我们启动文本编辑器并输入以下脚本:

我们脚本的最后一行很熟悉;它只是一个带有字符串参数的 echo 命令。第二行也很熟悉。它看起来像是我们在检查和编辑的许多配置文件中看到的注释。关于shell脚本中的注释,有一点是它们也可能出现在行尾,前提是它们前面至少有一个空格字符,如下所示:

从#符号开始的所有内容都会被忽略。

与许多事情一样,这也适用于命令行:

虽然注释在命令行上用处不大,但它们会起作用。

我们j脚本的第一行有点神秘。它看起来应该是一个注释,因为它以#开头,但它看起来太有目的(purposeful)了,不能只是这样。事实上,#! 字符序列是一种称为 shebang 的特殊结构。shebang用于告诉内核应该用于执行以下脚本的解释器的名称。每个shell脚本都应该将其作为第一行。

让我们将脚本文件另存为 hello_world

可执行权限

接下来我们要做的就是让我们的脚本可执行。这很容易用 chmod 完成。

脚本有两种常见的权限设置: 755 用于每个人都可以执行的脚本, 700 用于只有所有者才能执行的脚本。请注意,脚本必须可读才能执行

脚本文件位置

设置权限后,我们现在可以执行我们的脚本:

要运行脚本,我们必须在脚本名称前加上显式路径。如果我们不这样做,我们得到这个:

这是为什么?是什么让我们的脚本与其他程序不同?事实证明,什么都没有。我们的脚本很好。它的位置是问题所在。在【第11章】中,我们讨论了 PATH 环境变量及其对系统如何搜索可执行程序的影响。总而言之,如果没有指定显式路径,每次需要查找可执行程序时,系统都会搜索目录列表。当我们在命令行中键入 ls 时,系统就是这样知道执行 /bin/ls 的。 /bin 目录是系统自动搜索的目录之一。目录列表保存在名为PATH的环境变量中。PATH变量包含一个用冒号分隔的要搜索的目录列表。我们可以查看PATH的内容。

这里我们看到了我们的目录列表。如果我们的脚本位于列表中的任何目录中,我们的问题就会得到解决。请注意列表中的第一个目录 /home/me/bin 。大多数Linux发行版将PATH变量配置为在用户的主目录中包含一个 bin 目录,以允许用户执行自己的程序。因此,如果我们创建 bin 目录并将脚本放入其中,它应该开始像其他程序一样工作。

确实如此。

如果PATH 变量不包含目录,我们可以通过在 .bashrc 文件中包含此行来轻松添加它:

进行此更改后,它将在每个新的终端会话中生效。要将更改应用于当前的终端会话,我们必须让shell重新读取 .bashrc 文件。这可以通过“sourcing”来实现。

点(.)命令是 source 命令的同义词, source 命令是一个内置的shell命令,它读取指定的shell命令文件,并将其视为来自键盘的输入。

注意:如果执行用户的 .bashrc 文件时 ~/bin 目录存在,Ubuntu(和大多数其他基于Debian的发行版)会自动将 ~/bin 目录添加到PATH变量中。因此,在Ubuntu系统上,如果我们创建 ~/bin 目录,然后注销并重新登录,一切正常。

【FreeBSD默认会将 ~/bin 添加到用户路径中,不管这个目录是否存在】

脚本的好位置

~/bin 目录是放置个人使用脚本的好地方。如果我们编写一个允许系统上每个人使用的脚本,传统位置是 /usr/local/bin 。供系统管理员使用的脚本通常位于 /usr/local/sbin 。在大多数情况下,本地提供的软件,无论是脚本还是编译程序,都应放在 /usr/local 层次结构中,而不是 /bin/usr/bin 中。这些目录由Linux文件系统层次结构标准指定,仅包含Linux发行商提供和维护的文件。

更多格式化技巧

严肃的脚本写作的一个关键目标是易于维护,即作者或其他人可以轻松修改脚本以适应不断变化的需求。使脚本易于阅读和理解是方便维护的一种方法。

长选项名

我们研究过的许多命令都有短选项名和长选项名。例如, ls 命令有许多选项,可以用短或长的形式表示。例如,以下内容:

它等效于以下命令:

为了减少键入,在命令行上输入选项时,首选短选项,但在编写脚本时,长选项可以提高可读性。

缩进和行延续

当使用长命令时,可以通过将命令分散到几行来提高可读性。在【第17章】中,我们看了一个特别长的 find 命令示例。

显然,这个命令乍一看有点难理解。在脚本中,如果这样编写,此命令可能更容易理解:

通过使用换行符(反斜杠换行序列)和缩进,读者可以更清楚地描述这个复杂命令的逻辑。这种技术也适用于命令行,尽管很少使用,因为它很难打字和编辑。脚本和命令行之间的一个区别是,脚本可以使用制表符来实现缩进,而命令行则不能,因为制表符用于激活补全。

配置vim进行脚本编写

vim文本编辑器有很多配置设置。有几个常见的选项可以促进脚本编写。

以下内容将启用语法突出显示:

使用此设置,查看脚本时,shell语法的不同元素将以不同颜色显示。这有助于识别某些类型的编程错误。它看起来也很酷。请注意,要使此功能正常工作,您必须安装完整版本的 vim ,并且您正在编辑的文件必须有一个shebang,表明该文件是一个shell脚本。如果您在使用前一个命令时遇到困难,请尝试 :set syntax=sh

下面将启用突出显示搜索结果的选项。

假设我们搜索单词 echo 。启用此选项后,单词的每个实例都将突出显示。

以下设置制表符占用的列数:

默认值为八列。将该值设置为4(这是一种常见的做法)可以更容易地在屏幕上显示长行。

以下操作将启用“自动缩进(auto indent)”功能:

这会导致vim缩进与刚才键入的行相同数量的新行。这加快了多种编程构造的键入速度。要停止缩进,请按 Ctrl-d

通过在 ~/.vimrc 文件中添加这些命令(不带前导冒号),可以使这些更改永久化。

总结

在脚本编写的第一章中,我们研究了如何编写脚本并使其在我们的系统上轻松执行。我们还看到了如何使用各种格式化技术来提高脚本的可读性(从而提高可维护性)。在接下来的章节中,易维护性将一次又一次地成为优秀脚本写作的核心原则。