1、Shell脚本概述
在一些复杂的Linux维护工作中,大量的重复性的输入和交互操作不仅费力费时,而且容易出错,而编写一个恰到好处的Shell脚本程序,可以批量处理、自动化地完成一系列维护任务,大大减轻管理员的负担。
Shell脚本是什么?
简单的说,只要将平时使用的各种Linux命令按顺序保存到一个文本文件中,然后添加可执行权限,这个文件就成为一个Shell脚本了。
1.1 Shell的作用
Shell是一个特殊的应用程序,它介于操作系统内核与用户之间,充当了命令解释器的角色。
Shell——负责接收用户输入的操作指令(命令)并解释,将需要执行的操作传递给内核执行,并输出执行结果。
注:常见的Shell解释器程序有很多种,使用不同的Shell时,其内部指令、命令行提示符等方面会存在一些区别。
可通过查看/etc/shell文件来了解当前系统所支持的Shell脚本种类。如下图:
1.2 编写第一个Shell脚本
Bash——是目前大多数Linux版本采用的默认Shell,是最受欢迎的开源软件项目之一。
例如,执行下图操作可以创建第一个脚本文件:first.sh
在上图的first.sh脚本文件中,包括三条命令,执行此脚本文件后,输出结果与依次单独执行这三条命令是相同的。如下图,是查看执行first.sh脚本文件后的结果:
补充:执行脚本的方式有两种,以执行上面所述的first.sh脚本文件为例。
一种是直接通过./first.sh的方式来执行脚本,但这要求文件本身具有x权限(在某些安全系统中可能无法满足此条件)
另一种是指定某个Shell来解释脚本语句,或者通过内部命令source(或点号.)来加载文件中的源代码执行。例如,使用sh first.sh或.first.sh也可以执行first.sh脚本中的语句。
注意:Linux系统中包括大量的Shell脚本文件,但应避免直接修改系统内的Shell脚本文件,以免导致服务或系统故障。
2、重定向与管道操作
由于Shell脚本批量处理的特性,其大部分操作过程会以静默的方式运行(不需要用户干预)
因此,学会提取、过滤执行信息就变得十分重要。
2.1 重定向操作
用户通过操作系统处理信息的过程中,包括下面这几类的交互设备文件:
- 标准输入(STDIN):默认的设备是键盘,文件编号为0。命令将从标准输入文件中读取在执行过程中需要的输入数据。
- 标准输出(STDOUT):默认的设备是显示器,文件编号为1.命令将执行后的输出结构=果发送到标准输出文件。
- 标准错误(STDERR):默认的设备是显示器,文件编号为2。命令将执行期间的各种错误信息发送到标准错误文件。
注:在实际的Linux系统维护中,可以改变输入、输出内容的方向,而不使用默认的标准输入、输出设备(键盘和显示器),这种操作称为重定向。
(1)、重定向输出
将命令的正常输出结果保存到指定的文件中,而不是直接显示在显示器的屏幕上。
注:重定向输出使用>(用于覆盖文件)或>>(用于追加文件)操作符号。
若重定向输出的目标文件不存在,则会新建该文件,然后将前面命令的输出结果保存到该文件中;
若目标文件已经存在,则将输出结果覆盖或追加到文件中。
例如,要将当前主机的CPU类型信息(uname -p)保存到kernel.txt文件中,而不是直接显示在屏幕上,可执行下图中的操作:
当需要保留目标文件原有的内容时,应使用>>操作符号,以便追加内容而不是全部覆盖。
例如,执行下图中的命令可以将内核版本信息追加到kernel.txt文件中:
(2)、重定向输入
指的是将命令中接收输入的途径由默认的键盘改为指定的文件,而不是等待从键盘输入。重定向输入使用<操作符
注:重定向输入可以使一些交互式操作过程能够通过读取文件来完成。
例如,使用passwd命令为用户设置密码时,每次都必须根据提示输入两次密码字串,非常繁琐。如下图:
但是若改成改用重定向输入将可以省略交互式的过程,而自动完成密码设置(结合passwd命令的--stdin选项来识别标准输入):
注:非交互式的命令语句,可以更方便的在Shell脚本中使用,从而大大减少程序被打断的过程,提高脚本执行的效率。
(3)、错误重定向
指的是将执行命令过程中出现的错误信息(如选项或参数错误)保存到指定的文件,而不是直接显示在屏幕上。
注:错误重定向使用2>操作符,其中的2是指错误文件的编号
(在使用标准输出、标准输入定向时,实际上省略了1、0编号)
例如,执行下图中的命令可以将使用tar命令进行备份时出现地错误信息保存到error.log文件中:
2.2 管道操作
位于管道符号|左侧的命令输出的结果,将作为右侧命令的输入(处理对象)。
注:同一行命令中,可以使用多个管道。管道操作通常用来过滤所需要的关键信息。
例如,使用grep命令查询使用/bin/bash作为Shell的系统用户名时,会输出符合条件的整行内容,在此基础上,可以结合管道操作与awk命令作进一步过滤,只输出用户名和登录Shell列:
3、Shell变量的作用、类型
Shell变量是用来存放系统和用户需要使用的特点参数(值),这些参数可以根据用户的设定或系统环境的变化而相应地变化。
常见Shell变量的类型有:
- 自定义变量
- 环境变量
- 只读变量
- 位置变量
- 预定义变量
3.1 自定义变量
自定义变量是由系统用户自己定义的变量,只在用户自己的Shell环境中有效,因此又称为本地变量。
注:在Bash中定义一个新的变量时,一般不需要提前进行声明,而是直接指定变量名称并赋给初始值内容即可。
定义变量的基本格式是“变量名=变量值”,等号两边没有空格。
变量名称要以字母、下划线开头,数字不能开头。另外,变量名称中不要包含特殊字符(如+ - * / ?& #等)。
例如,要定义一个Product的变量(值为Python)和一个名为Version的变量,可执行如下图的操作:
3.2 查看和引用变量的值
通过在变量名称前添加前导符号$,就可以引用一个变量的值。
注:使用echo命令可以查看变量(可以在一条echo中同时查看多个变量值)。如下图:
当变量名称容易和紧跟其后的其他字符相混淆时,需要用大括号{}将其括起来。如下图:
3.3 给变量赋值的特殊操作
在等号=后边直接指定变量内容是为变量赋值的最基本方法,除此之外还有一些特殊的赋值操作。
(1)双引号" "
双引号主要起到界定字符的作用,特别是当要赋值的内容中包含空格时,必须以双引号括起来。其他情况下可以省略。例如:
注:在双引号范围内,使用$符号可以引用其他变量的值(变量引用),从而能够直接调用现有变量的值来赋给新的变量。
例如,执行下图中的操作可以调用变量Version的值,将其赋给一个新的变量PyVersion:
(2)单引号' '
当要赋值的内容中包含$ " \等具有特殊含义的字符时,应该使用单引号括起来。
注:在单引号的范围内,将无法引用其他变量的值,任何字符均作为普通字符看待。
例如下图,
补充:当赋值内容中包含单引号时,需要使用\'符号进行转义,以免冲突,如下图:
(3)反撇号`
反撇号主要用于命令替换,允许将执行某个命令的屏幕输出结果赋值给变量。
注:反撇号括起来的范围内必须是能够执行的命令行,否则将会出错。
如下图,
在上图中的操作,相当于连续执行了两条命令——先通过which useradd命令查找出useradd命令的程序位置,然后根据查找结果列出其文件属性。
也就是说,执行过程中,会用which useradd命令的输出结果替换整个反撇号范围。
(4)read命令
除了上述的赋值操作以外,还可以使用Bash的内置命令read来给变量赋值。
read命令——用来提示用户输入信息,从而实现简单的交互过程。
注:read命令在执行时,将从标准输入设备(键盘)读入一行内容,并以空格为分隔符,将读入的各字段依次赋值给指定的变量(多余的内容赋值给最后一个变量)。
若指定的变量只有一个,则将整行内容赋值给此变量。
例如,执行下图中的命令将会等待用户输入文字,并将输入的内容赋值给变量ToDir1:
补充:为了使交互式操作界面更加友好,read命令可以结合-p选项来设置提示信息(以便告知用户应该输入什么内容等相关事项)。
例如,若希望提示用户输入备份文件的存放目录,并将输入的路径信息赋值给变量ToDir2,可以执行下图中的操作:
3.4 设置变量的作用范围
默认环境下,新定义的变量只在当前的Shell环境中有效,因此称为局部变量。
注:当进入到子程序或新的子Shell环境时,局部变量将无法再使用。
例如,直接执行Bash进入一个新的子Shell脚本后,将无法引用父级Shell环境中定义的Product、Version等变量。如下图:
为了使用户定义的变量在所有的子Shell环境中能够继续使用,减少重复设置工作,可以通过内部命令export将指定的变量导出为全局变量。
注:用户可以同时指定多个变量名称作为参数(无须使用$符号),变量名之间以空格分隔。
补充:在使用export导出全局变量的同时,也可以为变量进行赋值,这样一来,在新定义全局变量时就不需要提前进行赋值了。
例如,执行下图中的操作可以直接新建一个名为FQDN的全局变量:
4、数值变量的运算
Shell变量的数值运算多用于脚本程序的过程控制(如循环次数、使用量比较等)。
注:在Bash Shell环境中,只能进行简单的整数运算,不支持小数运算。
整数值的运算主要通过内部命令expr进行,基本格式如下所示:
但要注意,运算符与变量之间必须有至少一个空格。
常用的运算符有:
+ 加法运算
- 减法运算
\* 乘法运算 (注意不能仅使用*符号,否则将被当成文件通配符)
/ 除法运算
% 取余运算——用来计算数值相除后的余数
若要将运算结果赋值给其他变量,可以结合命令替换操作(使用反撇号)。
例如,下图中为计算变量Y的三次方,并将结果赋值给变量Ycube:
5、特殊的Shell变量
除了用户自定义的Shell变量以外,在Linux系统和Bash Shell环境中还有一系列的特殊变量,它们分别是:
环境变量、只读变量、位置变量、预定义变量
5.1 环境变量——主要用于设置用户的工作环境(包括宿主目录、命令查找路径、用户当前目录、登录终端等)
环境变量是出于运行需要而由Linux系统提前创建的一类变量,
注:环境变量的值由Linux系统自动维护,会随着用户状态的改变而改变。
使用env命令——可以查看到当前工作环境下的环境变量。
接上图:
PATH变量——用于设置可执行程序的默认搜索路径,当仅指定文件名称来执行命令程序时,Linux系统将在PATH变量指定的目录范围查找对应的可执行文件,如果找不到则会提示command not found。
例如,first.sh脚本位于/root目录下,若希望能直接通过文件名称来运行脚本,可以修改PATH变量以添加搜索路径,或者直接将first.sh脚本复制到现有搜索路径中的某个文件夹下:
在Linux系统中,环境变量的全局配置文件为/etc/profile,在此文件中定义的变量作用于所有用户。
除此之外,每个用户还有自己的独立配置文件(~/.bash_profile)。
注:若要长期变更或设置某个环境变量,应该在/etc/profile文件中进行设置。
例如,执行以下操作可以将记录的历史命令条数改为200条(默认为1000条),只针对root用户:
在上图中的修改,只有当用户root用户下次登录时才会生效。若希望立即生效,应手动修改环境变量,或者加载配置文件执行:
5.2 只读变量
只读变量一经设定,其值是不可改变的。
注:在创建变量的时候,可将其设置为只读属性,也可以将已存在的变量设置为只读属性(只读变量——主要用于变量值不允许被修改的情况)
例如,脚本中定义了一个变量log_path用来定义日志文件的路径,在脚本的执行过程中如果不想被修改,就可以将该变量设置为只读变量。如下图:
补充:
readonly命令——可将变量定义为只读变量(定义之后不能通过再次赋值的方式进行修改)
unset命令——用于删除变量
5.3 位置变量
当执行命令行操作时,第一个字段表示命令名或脚本程序名,其余的字符串参数按照从左到右的顺序依次赋值给位置变量。
位置变量也称为位置参数,使用$1、$2、$3.....$9表示。
例如,当执行命令行ls -lh /boot时,其中第一个位置变量为-lh,以$1表示;
第二个位置变量为/boot,以$2表示;
命令或脚本本身的名称使用$0表示($0属于预定义变量而不是位置变量)
为了说明位置变量的作用,下面编写一个加法运算的小脚本adder2num.sh,用来计算两个整数的和。需要计算的两个整数在执行脚本时以位置变量的形式提供:
脚本的内容是:
5.4 预定义变量
预定义变量是由Bash程序预先定义好的一类特殊变量,预定义变量使用$符号和另一个符号组合表示。
注:用户只能使用预定义变量,而不能创建新的预定义变量,也不能直接为预定义变量赋值。
几个常用的预定义变量如下:
$#——表示命令行中位置参数的个数
$*——表示所有位置参数的内容
$?——表示前一条命令执行后的返回状态,
返回值为0表示执行正确,返回值为让任何非0值均表示执行出现异常
$0——表示当前执行的脚本或程序的名称