编写第⼀个shell脚本
在前⾯的章节中,我们已经装备了⼀个命令⾏⼯具的武器库。虽然这些⼯具能够解决许多种计算问题, 但是我们仍然局限于在命令⾏中⼿动地⼀个⼀个使⽤它们。难道不是很棒,如果我们能够让 shell 来完成更多的⼯作? 我们可以的。通过把我们的⼯具⼀起放置到我们⾃⼰设计的程序中,然后 shell 就会⾃⼰来执⾏这些复杂的任务序列。 通过编写 shell 脚本,我们让 shell 来做这些事情。
什么是 Shell 脚本?
最简单的解释,⼀个 shell 脚本就是⼀个包含⼀系列命令的⽂件。shell 读取这个⽂件,然后执⾏ ⽂件中的所有命令,就好像这些命令已经直接被输⼊到了命令⾏中⼀样。
Shell 有些独特,因为它不仅是⼀个功能强⼤的命令⾏接⼝,也是⼀个脚本语⾔解释器。我们将会看到, ⼤多数能够在命令⾏中完成的任务也能够⽤脚本来实现,同样地,⼤多数能⽤脚本实现的操作也能够 在命令⾏中完成。
虽然我们已经介绍了许多 shell 功能,但只是集中于那些经常直接在命令⾏中使⽤的功能。 Shell 也提供了⼀些通常(但不总是)在编写程序时才使⽤的功能。
怎样编写⼀个 Shell 脚本
为了成功地创建和运⾏⼀个 shell 脚本,我们需要做三件事情:
1. 编写⼀个脚本。 Shell 脚本就是普通的⽂本⽂件。所以我们需要⼀个⽂本编辑器来书写它们。最好的⽂本 编辑器都会⽀持语法⾼亮,
这样我们就能够看到⼀个脚本关键字的彩⾊编码视图。语法⾼亮会帮助我们查看某种常见 错误。为了编写脚本⽂
件,vim,gedit,kate,和许多其它编辑器都是不错的候选者。
2. 使脚本⽂件可执⾏。 系统会相当挑剔不允许任何旧的⽂本⽂件被看作是⼀个程序,并且有充分的理由! 所以我们需要设置脚本⽂件的
权限来允许其可执⾏。
3. 把脚本放置到 shell 能够到的地⽅ 当没有指定可执⾏⽂件明确的路径名时,shell 会⾃动地搜索某些⽬录, 来查此可执⾏⽂件。
为了最⼤程度的⽅便,我们会把脚本放到这些⽬录当中。
脚本⽂件格式
为了保持编程传统,我们将创建⼀个 “hello world” 程序来说明⼀个极端简单的脚本。所以让我们启动 我们的⽂本编辑器,然后输⼊以下脚本:
#!/bin/bash
# This is our first script.
echo 'Hello World!'
对于脚本中的最后⼀⾏,我们应该是相当的熟悉,仅仅是⼀个带有⼀个字符串参数的 echo 命令。 对于第⼆⾏也很熟悉。它看起来像⼀个注释,我们已经在许多我们检查和编辑过的配置⽂件中 看到过。关于 shell 脚本中的注释,它们也可以出现在⽂本⾏的末尾,像这样:
echo 'Hello World!' # This is a comment too
⽂本⾏中,# 符号之后的所有字符都会被忽略。
类似于许多命令,这也在命令⾏中起作⽤:
[me@linuxbox ~]$ echo 'Hello World!' # This is a comment too
Hello World!
虽然很少在命令⾏中使⽤注释,但它们也能起作⽤。
我们脚本中的第⼀⾏⽂本有点⼉神秘。它看起来它应该是⼀条注释,因为它起始于⼀个#符号,但是 它看起来太有意义,以⾄于不仅仅是注释。事实上,这个#!字符序列是⼀种特殊的结构叫做 shebang。 这个 shebang 被⽤来告诉操作系统将执⾏此脚本所⽤的解释器的名字。每个 shell 脚本都应该把这⼀⽂本⾏ 作为它的第⼀⾏。
让我们把此脚本⽂件保存为 hello_world。
可执⾏权限
下⼀步我们要做的事情是让我们的脚本可执⾏。使⽤ chmod 命令,这很容易做到:
[me@linuxbox ~]$ ls -l hello_world
-rw-r--r-- 1 me me 63 2009-03-07 10:10 hello_world
[me@linuxbox ~]$ chmod 755 hello_world
[me@linuxbox ~]$ ls -l hello_world
-rwxr-xr-x 1 me me 63 2009-03-07 10:10 hello_world
对于脚本⽂件,有两个常见的权限设置;权限为755的脚本,则每个⼈都能执⾏,和权限为700的 脚本,只有⽂件所有者能够执⾏。注意为了能够执⾏脚本,脚本必须是可读的。
脚本⽂件位置
当设置了脚本权限之后,我们就能执⾏我们的脚本了:
[me@linuxbox ~]$ ./hello_world
Hello World!
为了能够运⾏此脚本,我们必须指定脚本⽂件明确的路径。如果我们没有那样做,我们会得到这样的提⽰:
[me@linuxbox ~]$ hello_world
bash: hello_world: command not found
为什么会这样呢?什么使我们的脚本不同于其它的程序?结果证明,什么也没有。我们的 脚本没有问题。是脚本存储位置的问题。回到第12章,我们讨论了 PATH 环境变量及其它在系统 查可执⾏程序⽅⾯的作⽤。回顾⼀下,如果没有给出可执⾏程序的明确路径名,那么系统每次都会 搜索⼀系列的⽬录,来查此可执⾏程序。这个/bin ⽬录就是其中⼀个系统会⾃动搜索的⽬录。 这个⽬录列表被存储在⼀个名为 PATH 的环境变量中。这个 PATH 变量包含⼀个由冒号分隔开的⽬录列表。 我们可以查看 PATH 的内容:
[me@linuxbox ~]$ echo $PATH
/home/me/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:
/bin:/usr/games
这⾥我们看到了我们的⽬录列表。如果我们的脚本驻扎在此列表中任意⽬录下,那么我们的问题将 会被解决。注意列表中的第⼀个⽬
录,/home/me/bin。⼤多数的 Linux 发⾏版会配置 PATH 变量,让其包含 ⼀个位于⽤户家⽬录下的 bin ⽬录,从⽽允许⽤户能够执⾏他们⾃⼰的程序。所以如果我们创建了 ⼀个 bin ⽬录,并把我们的脚本放在这个⽬录下,那么这个脚本就应该像其它程序⼀样开始⼯作了:
[me@linuxbox ~]$ mkdir bin
[me@linuxbox ~]$ mv hello_world bin
[me@linuxbox ~]$ hello_world
Hello World!
它的确⼯作了。
如果这个 PATH 变量不包含这个⽬录,我们能够轻松地添加它,通过在我们的.bashrc ⽂件中包含下⾯ 这⼀⾏⽂本:
export PATH=~/bin:"$PATH"
shell最简单脚本当做了这个修改之后,它会在每个新的终端会话中⽣效。为了把这个修改应⽤到当前的终端会话中, 我们必须让 shell 重新读取这个
.bashrc ⽂件。这可以通过 “sourcing”.bashrc ⽂件来完成:
[me@linuxbox ~]$ . .bashrc
这个点(.)命令是 source 命令的同义词,⼀个 shell 内部命令,⽤来读取⼀个指定的 shell 命令⽂件, 并把它看作是从键盘中输⼊的⼀样。
注意:在 Ubuntu 系统中,如果存在 ~/bin ⽬录,当执⾏⽤户的 .bashrc ⽂件时, Ubuntu 会⾃动地添加这个 ~/bin ⽬录到 PATH 变量中。所以在 Ubuntu 系统中,如果我们创建 了这个 ~/bin ⽬录,随后退出,然后再登录,⼀切会正常运⾏。
脚本⽂件的好去处
这个 ~/bin ⽬录是存放为个⼈所⽤脚本的好地⽅。如果我们编写了⼀个脚本,系统中的每个⽤户都可以使⽤它, 那么这个脚本的传统位置是 /usr/local/bin。系统管理员使⽤的脚本经常放到 /usr/local/sbin ⽬录下。 ⼤多数情况下,本地⽀持的软件,不管是脚本还是编译过的程序,都应该放到 /usr/local ⽬录下, ⽽不是在 /bin 或 /usr/bin ⽬录下。这些⽬录都是由 Linux ⽂件系统层次结构标准指定,只包含由 Linux 发⾏商 所提供和维护的⽂件。
更多的格式技巧
严肃认真的脚本书写,⼀个关键⽬标是为了维护⽅便;也就是说,⼀个脚本可以轻松地被作者或其它 ⽤户修改,使它适应变化的需求。使脚本容易阅读和理解是⼀种⽅便维护的⽅法。
长选项名称
我们学过的许多命令都以长短两种选项名称为特征。例如,这个 ls 命令有许多选项既可以⽤短形式也 可以⽤长形式来表⽰。例如:
[me@linuxbox ~]$ ls -ad
和:
[me@linuxbox ~]$ ls --all --directory
是等价的命令。为了减少输⼊,当在命令⾏中输⼊选项的时候,短选项更受欢迎,但是当书写脚本的时候, 长选项能提供可读性。
缩进和⾏继续符
当雇佣长命令的时候,通过把命令在⼏个⽂本⾏中展开,可以提⾼命令的可读性。 在第⼗⼋章中,我们看到了⼀个特别长的 find 命令实例:
[me@linuxbox ~]$ find playground \( -type f -not -perm 0600 -exec
chmod 0600 ‘{}’ ‘;’ \) -or \( -type d -not -perm 0711 -exec chmod
0711 ‘{}’ ‘;’ \)
显然,这个命令有点⼉难理解,当第⼀眼看到它的时候。在脚本中,这个命令可能会⽐较容易 理解,如果这样书写它:
find playground \
\( \
-type f \
-not -perm 0600 \
-exec chmod 0600 ‘{}’ ‘;’ \
\) \
-or \
\( \
-type d \
-not -perm 0711 \
-exec chmod 0711 ‘{}’ ‘;’ \
\)
通过使⽤⾏继续符(反斜杠-回车符序列)和缩进,这个复杂命令的逻辑性更清楚地描述给读者。 这个技巧在命令⾏中同样⽣效,虽然很少使⽤它,因为输⼊和编辑这个命令⾮常⿇烦。脚本和 命令⾏的⼀个区别是,脚本可能雇佣 tab 字符拉实现缩进,然⽽命令⾏却不能,因为tab 字符被⽤来 激活⾃动补全功能。
为书写脚本配置 vim
这个 vim ⽂本编辑器有许多许多的配置设置。有⼏个常见的选项能够有助于脚本书写:
:syntax on
打开语法⾼亮。通过这个设置,当查看脚本的时候,不同的 shell 语法元素会以不同的颜⾊ 显⽰。这
对于识别某些编程错误很有帮助。并且它看起来也很酷。注意为了这个功能起作⽤,你 必须安装了⼀个完整的 vim 版本,并且你编辑的⽂件必须有⼀个
shebang,来说明这个⽂件是 ⼀个 shell 脚本。如果对于上⾯的命令,你遇到了困难,试试 :set syntax=sh。
:set hlsearch
打开这个选项是为了⾼亮查结果。⽐如说我们查单词“echo”。通过设置这个选项,这个 单词的每个实例会⾼亮显⽰。
:set tabstop=4
设置⼀个 tab 字符所占据的列数。默认是8列。把这个值设置为4(⼀种常见做法), 从⽽让长⽂本⾏更容易适应屏幕。
:set autoindent
打开 “auto indent” 功能。这导致 vim 能对新的⽂本⾏缩进与刚输⼊的⽂本⾏相同的列数。 对于许多编程结构来说,这就加速了输⼊。停⽌缩进,输⼊ Ctrl-d。
通过把这些命令(没有开头的冒号字符)添加到你的 ~/.vimrc ⽂件中,这些改动会永久⽣效。
总结归纳
在这脚本编写的第⼀章中,我们已经看过怎样编写脚本,怎样让它们在我们的系统中轻松地执⾏。 我们也知道了怎样使⽤各种格式技巧来提⾼脚本的可读性(可维护性)。在以后的各章中,轻松维护 会作为编写好脚本的中⼼法则⼀次⼜⼀次地出现。
拓展阅读
查看各种各样编程语⾔的“Hello World”程序和实例:
这篇 Wikipedia ⽂章讨论了更多关于 shebang 机制的内容:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论