1、编写Shell脚本
可以将Shell终端解释器当作人与计算机硬件之间的“翻译官”,它作为用户与Linux系统内部的通信媒介,除了能够支持各种变量与参数外,还提供了诸如循环、分支等高级编程语言才有的控制结构特性。要想正确使用Shell中的这些功能特性,准确下达命令尤为重要。Shell脚本命令的工作方式有下面两种。
交互式(Interactive):用户每输入一条命令就立即执行。
批处理(Batch):由用户事先编写好一个完整的Shell脚本,Shell会一次性执行脚本中诸多的命令。
在Shell脚本中不仅会用到前面学习过的很多Linux命令以及正则表达式、管道符、数据流重定向等语法规则,还需要把内部功能模块化后通过逻辑语句进行处理,最终形成日常所见的Shell脚本。
通过查看SHELL变量可以发现,当前系统已经默认使用Bash作为命令行终端解释器了:
[root@localhost ~]# echo $SHELL /bin/bash
1、编写简单的脚本
估计读者在看完上文中有关Shell脚本的复杂描述后,会累觉不爱吧。但是,上文指的是一个高级Shell脚本的编写原则,其实使用Vim编辑器把Linux命令按照顺序依次写入到一个文件中,就是一个简单的脚本了。
例如,如果想查看当前所在工作路径并列出当前目录下所有的文件及属性信息,实现这个功能的脚本应该类似于下面这样:
[root@localhost ~]# vim example.sh #!/bin/bash # 这是一句注释 pwd ls -al
Shell脚本文件的名称可以任意,但为了避免被误以为是普通文件,建议将.sh后缀加上,以表示是一个脚本文件。
在上面的这个example.sh脚本中实际上出现了3种不同的元素:第一行的脚本声明(#!)用来告诉系统使用哪种Shell解释器来执行该脚本;第二行的注释信息(#)是对脚本功能和某些命令的介绍信息,使得自己或他人在日后看到这个脚本内容时,可以快速知道该脚本的作用或一些警告信息;第三、四行的可执行语句也就是我们平时执行的Linux命令了。你们不相信这么简单就编写出来了一个脚本程序?!那我们来执行一下看看结果:
[root@localhost ~]# bash example.sh /root total 60 dr-xr-x---. 15 root root 4096 Oct 12 00:41 . dr-xr-xr-x. 17 root root 224 Jul 21 05:04 .. -rw-------. 1 root root 1407 Jul 21 05:09 anaconda-ks.cfg -rw-------. 1 root root 335 Jul 24 06:33 .bash_history -rw-r--r--. 1 root root 18 Aug 13 2018 .bash_logout -rw-r--r--. 1 root root 176 Aug 13 2018 .bash_profile ………………省略部分输出信息………………
除了上面用Bash解释器命令直接运行Shell脚本文件外,第二种运行脚本程序的方法是通过输入完整路径的方式来执行。但默认会因为权限不足而提示报错信息,此时只需要为脚本文件增加执行权限即可(详见第5章)。初次学习Linux系统的读者不用心急,等下一章学完用户身份和权限后再来做这个实验也不迟:
[root@localhost ~]# ./example.sh bash: ./Example.sh: Permission denied [root@localhost ~]# chmod u+x example.sh [root@localhost ~]# ./example.sh /root total 60 dr-xr-x---. 15 root root 4096 Oct 12 00:41 . dr-xr-xr-x. 17 root root 224 Jul 21 05:04 .. -rw-------. 1 root root 1407 Jul 21 05:09 anaconda-ks.cfg -rw-------. 1 root root 335 Jul 24 06:33 .bash_history -rw-r--r--. 1 root root 18 Aug 13 2018 .bash_logout -rw-r--r--. 1 root root 176 Aug 13 2018 .bash_profile ………………省略部分输出信息………………
2、接收用户的参数
但是,像上面这样的脚本程序只能执行一些预先定义好的功能,未免太过死板。为了让Shell脚本程序更好地满足用户的一些实时需求,以便灵活完成工作,必须要让脚本程序能够像之前执行命令时那样,接收用户输入的参数。
比如,当用户执行某一个命令时,加或不加参数的输出结果是不同的:
[root@localhost ~]# wc -l anaconda-ks.cfg 44 anaconda-ks.cfg [root@localhost ~]# wc -c anaconda-ks.cfg 1407 anaconda-ks.cfg [root@localhost ~]# wc -w anaconda-ks.cfg 121 anaconda-ks.cfg
这意味着命令不仅要能接收用户输入的内容,还要有能力进行判断区别,根据不同的输入调用不同的功能。
其实,Linux系统中的Shell脚本语言早就考虑到了这些,已经内设了用于接收参数的变量,变量之间使用空格间隔。例如,$0对应的是当前Shell脚本程序的名称,$#对应的是总共有几个参数,$对应的是所有位置的参数值,$?对应的是显示上一次命令的执行返回值,而$1、$2、$3……则分别对应着第N*个位置的参数值,如图所示。
理论过后再来练习一下。尝试编写一个脚本程序示例,通过引用上面的变量参数来看一下真实效果:
[root@localhost ~]# vim example.sh #!/bin/bash echo "当前脚本名称为$0" echo "总共有$#个参数,分别是$*。" echo "第1个参数为$1,第5个为$5。" [root@localhost ~]# bash example.sh one two three four five six 当前脚本名称为example.sh 总共有6个参数,分别是one two three four five six。 第1个参数为one,第5个为five。
3、判断用户的参数
学习是一个登堂入室、由浅入深的过程。在学习完Linux命令,掌握Shell脚本语法变量和接收用户输入的信息之后,就要踏上新的高度—能够进一步处理接收到的用户参数。
本书在前面章节中讲到,系统在执行mkdir命令时会判断用户输入的信息,即判断用户指定的文件夹名称是否已经存在,如果存在则提示报错;反之则自动创建。Shell脚本中的条件测试语法可以判断表达式是否成立,若条件成立则返回数字0,否则便返回非零值。条件测试语法的执行格式如图4-16所示。切记,条件表达式两边均应有一个空格。
按照测试对象来划分,条件测试语句可以分为4种:
文件测试语句;
逻辑测试语句;
整数值比较语句;
字符串比较语句。
文件测试即使用指定条件来判断文件是否存在或权限是否满足等情况的运算符,具体的参数如表所示。
操作符 | 作用 |
---|---|
-d | 测试文件是否为目录类型 |
-e | 测试文件或文件夹是否存在 |
-f | 判断是否为一般文件 |
-r | 测试当前用户是否有权限读取 |
-w | 测试当前用户是否有权限写入</ |