Shell脚本学习指南

发布时间:2025-12-09 20:46:38 浏览次数:4

目录

  • 一、Shell脚本基础知识
    • 1、什么是Shell脚本?
    • 2、常见的Shell类型
    • 3、如何查询Shell环境
      • 1)使用cat命令查看配置文件/etc/shells可以查看当前系统支持的Shell环境
      • 2)通过环境变量SHELL或者用户配置文件/etc/passwd可以查询当前用户的Shell环境
    • 4、如何切换Shell环境
      • 1)临时切换
      • 2)永久修改
    • 5、Shell变量
      • echo命令
      • printf命令
      • 1)本地变量
        • a.定义变量
        • b.引用和打印变量值
        • c.查询和删除本地变量
        • d.从控制台给变量赋值
        • e.本地变量的运算符
        • f.expr数值运算命令
        • g.双小括号(())数值运算
        • h.$[]数值运算
      • 2)环境变量
      • 3)位置变量
      • 4)特殊变量
  • 二、认识Shell脚本
    • 1、Shell脚本格式
      • 1)Shell脚本中常用的符号说明
      • 2)Shell脚本的编写
    • 2、Shell脚本的运行方式
    • 3、Shell脚本简单示例
  • 三、流程控制语句
    • 1、条件测试表达式
      • 1)文件状态比较
      • 2)整数值比较
      • 3)字符串比较
      • 4)逻辑测试
    • 2、if判断语句
      • 1)单条件if语句
      • 2)双条件if语句
      • 3)多条件if语句
    • 3、循环语句
      • 1)for循环语句
      • 2)while循环语句
      • 3)until循环语句
    • 4、循环控制语句
      • 1)break语句
      • 2)continue语句
      • 3)exit语句
    • 5、选择语句
      • 1)case多重分支语句
      • 2)select选择语句
      • 3)case和select语句的结合使用
  • 四、Shell函数
    • 1、函数的定义和调用
    • 2、向函数传递参数
    • 3、函数返回值
    • 4、函数调用
      • 1)脚本放置多个函数
      • 2)函数相互调用
      • 3)一个函数调用多个函数
    • 5、局部变量和全局变量

一、Shell脚本基础知识

1、什么是Shell脚本?

在学习Shell脚本之前,首先需要明白Shell脚本到底是什么。Shell脚本简单来说就是一个命令解释器,它是介于操作系统内核与用户之间,负责将用户输入的命令传递给系统内核进行执行,然后将结果输出到终端上给用户。其作用相当于一个“翻译官”。Shell脚本是偏向于操作系统层面的脚本编程语言,相对于其他高级编程语言,Shell脚本更加适合对系统方面进行管理。

2、常见的Shell类型

在Linux系统中,常见的Shell类型有Bash、Bsh(sh)、Csh、Dash、Ksh、Rbash和Zsh

.Bash是Bourne Again Shell的缩写,是为GNU项目设计的,是Linux发行版默认使用的Shell。
.Bsh(sh)是Bourne Shell的缩写,是较早的UNIX Shell程序,实现了最基本的命令解释功能。
.Csh是C shell的缩写,使用的是“类C”语法,具备C语言的风格,共有52个内部命令,它在交互式界面方面改进了许多,更多适合用户操作。
.Dash是Debian Almquist shell的缩写,Dash Shell比Bash Shell小的多,符合POSIX标准。
.Ksh是Korn Shell的缩写,它结合Bsh和Csh的优点,基于Bsh的源代码发展而来,在UNIX系统中使用较多。
.Rbash是是Resticted Bash的缩写,即受限制的bash。其可以用作中转服务器,或者仅使用ssh来访问网页等等。
.Zsh是Z Shell的缩写,有84个Linux内部命令,添加了Bash、Csh和Ksh的特性,命令功能完善,会逐步成为Bash的替代品。

3、如何查询Shell环境

以ubunut系统为例讲解如何查询该系统支持的Shell环境。

1)使用cat命令查看配置文件/etc/shells可以查看当前系统支持的Shell环境

2)通过环境变量SHELL或者用户配置文件/etc/passwd可以查询当前用户的Shell环境

4、如何切换Shell环境

在使用系统的过程中,如果用户需要使用不同的Shell环境去操作命令,可以通过临时切换和永久修改两种方式实现。永久修改方式需要重启之后才能生效。

1)临时切换

临时切换用户的Shell环境只是临时调用,重启之后就失效了,可以通过/etc/shells文件查询系统支持的Shell环境,在Linux中直接使用Shell名或者绝对路径。

将当前用户的Shell环境从bin/bash切换成/bin/sh,使用Shell名或者绝对路径:

使用exit命令返回原来的Shell环境:

2)永久修改

如果要将用户的Shell环境永久修改,可以通过usermod和chsh两条命令来实现,其中Shell名一定要使用绝对路径加名称(可以通过查询/etc/shells文件获取)。注意,需要重启用户之后用户下次登录时才会生效。命令格式如下:
usermod -s Shell名 用户名
usermod -s Shell名 用户名

使用usermod命令修改zxw用户的Shell环境为/bin/sh:

使用chsh命令修改zxw用户的Shell环境为/bin/sh:

5、Shell变量

在编写Shell脚本时需要用到Shell变量。变量通常使用特定的字符(一般是以下划线或字母开头)表示,它用来存储数据,只不过这些数据是随着系统或用户设定的变化而变化的。变量的赋值采用表达式的方式,即“变量名=变量值”,其中等于号“=”表示赋值,意思是将右边的变量赋值给左边的变量名。
在Shell脚本中变量主要分为4类,即本地变量、环境变量、位置变量和特殊变量。
在介绍Shell变量之前,首先熟悉下几条命令的使用方式

echo命令

echo命令除了能够在屏幕上打印输出信息外,还可以输出变量的值。命令格式如下:
echo [选项] 字符串[特殊符号]
常用选项如下:
-n:打印输出不换行
-e:启用特殊符号(转义符)


示例:
#-n选项的使用:输出不换行,第一个是不使用“-n”的效果,第二个是使用“-n”的效果


#使用转义符
\b:退格,光标前移一格,并将之后的内容覆盖输出,其后无内容时,不覆盖本来已有内容。如图,a向前移一格,并覆盖3。

\c:不执行其后的内容输出,也不自动换行。如图,test后面的内容不输出,只输出test。

\n:换行。如图,输出test之后并换行输出123。

\r:回车,其后内容移至行首输入,覆盖之前的输入。如图,后面的内容ab移至行首输入,覆盖之前的内容12,输出结果ab3。

\v:垂直制表符。

\0nnn:插入nnn所代表的ASCII字符,n为八进制数字。大写A的ASCII值为65。下面使用进制数的转换。

printf命令

printf命令的特定在于能够控制输出的格式,因此在编写Shell脚本时,某些场景也会使用printf命令。命令格式如下:
printf 格式 字符串[特殊符号]
printf命令的常用类型转换符说明如下:

示例:
#使用转义符
\n:换行。

#类型转换符
使用%d、%.2f、%o和%x将参数12分别转换为十进制数、带两位小数的浮点数、八进制数和十六进制数、结合转义符“\n”实现换行输出

言归正传,我们来了解下Shell脚本的四种变量。

1)本地变量

本地变量就是用户自己定义的变量,也称为自定义变量,只在当前用户的Shell环境中生效。如果在Shell中启动另外一个进程或者退出一个进程,这个变量就失效了。

a.定义变量

变量名一般以下划线或字母开头,名称由字母、数字和下划线组合而成,通过表达式的形式定义,格式如下:
变量名=变量值
自定义变量分为局部变量和全局变量。如果在定义变量时使用关键字export,就表示该变量为全局变量,针对所有Shell环境都生效;否则就是局部变量,只是针对当前的Shell环境生效,切换到其他Shell环境就失效了。对于变量的值,也就是变量的内容,可以使用单引号、双引号、反撇号,也可以不使用任何引号。
·不加任何引号:一般针对数字、简单的字符和字符串,如果内容中存在变量会解析出变量的值。
·单引号(‘’):变量的内容是什么就会原样输出什么,当引号中存在变量名时,也会将变量名当作普通字符处理。
·双引号(“”):和不加任何引号是一样的,但有些变量的内容必须加上双引号,比如逻辑运算符中的乘号“*”。编写脚本时一般直接省略。
·反撇号(``):表示变量的内容是由命令执行的结果而来的,在复制给变量时必须使用。反撇号是键盘Tab键上面的键输出的字符。

示例:
定义全局变量x和局部变量y

b.引用和打印变量值

引用变量值需要在变量名前面添加符号“$”,例如“$变量名”,如果引用的变量值输出时还需要在后面接其他字符,则必须使用“{}”将变量名包裹起来。
将引用的变量值打印输出到屏幕上,可以使用echo或printf命令,如“echo $变量名”或者“printf “$变量名””。在后面的学习中,echo命令的使用频率高一点。

示例:
引用变量a的值,并将结果输出到屏幕上,分别使用单引号和双引号进行测试

在引用变量name的值后面接上其他字符输出,如果变量名不使用“{}”包裹,则输出为空

c.查询和删除本地变量

可以使用set命令查询所有变量,包括本地变量,可以使用unset命令删除变量。

示例:
查看本地变量,会列出当前Shell环境中的所有变量

删除自定义的变量a,然后再打印输出变量的值就为空

d.从控制台给变量赋值

可以使用read命令通过控制台(键盘)对变量进行赋值,如果使用选项“-p”就必须接上描述语,就算描述语为空都行,否则变量定义失败。在实际编写脚本时最好接上对应的描述语,相当于添加了提示语。命令格式如下:
read 选项 变量名
常用选项说明如下:
·-a:将输入的数据复制给数组array,下标从0开始,@表示全部。
·-d:指定输入行的结束符号,默认使用换行符。
·-n:指定输入的字符数,如果没有指定字符数且没有全部读取完,按Enter键也会结束。
·-N:严格限定输入的字符数,如果没有指定字符数且没有全部读取完,按Enter键也不会结束。其中,换行符或回车符也算一个字符。
·-p:指定描述语。
·-s:静默显示,输入的内容不会在屏幕上显示。
·-t:设置超时时间,默认单位为秒(s)。

示例:
将读取的数据赋值给数组变量array


限制从控制台输入4个字符数,输入未满4个也可以按Enter键直接结束

严格限制从控制台输入6个字符,未满6个无法按Enter键结束,回车符也占用一个字符

按Enter键也算一个字符

定义变量c,从控制台给变量赋值,使用描述语,会显示一段提示告诉使用者干什么

不使用描述语,从控制台给变量d赋值

使用选项“-p”,但后面不接描述语,就会出现变量定义失败的情况

e.本地变量的运算符

在定义数字变量特别是整数时离不开各种运算符。例如,在后续介绍循环语句时需要控制脚本的循环次数,此时便需要使用一些简单的整数运算。下面介绍常用的运算符。
(1)算术运算符
Shell并不属于高级编程语言,因此只能进行一些简单的整数运算,对于小数等复杂的数据运算是不适用的。关于整数的算术运算符如表所示,其中需要重点掌握加减乘除的使用,其他的可以作为参考进行了解。

(2)比较运算符
对于整数或字符的比较无非就是相同或不同,使用的运算符如表所示。


(3)赋值运算符
表达式“a=a+1”有时候也会写成“a+=1”的格式,其中“+=”便是赋值运算符。常用的赋值运算符如表所示。

f.expr数值运算命令

expr命令属于Shell脚本中的标准语法,对于整数数值运算,其命令格式如下:
expr 数值[变量]
运算符 数值[变量]
注意,数值(或变量)与运算符之间需要使用空格隔开。

示例:
通过整数值运算

通过定义变量的方式运算

g.双小括号(())数值运算

并不是所有的运算符都可以使用expr命令实现,例如幂次方、位运算、比较运算和赋值运算等复杂的整数计算需要借助双小括号实现。

示例:
求3的二次方

a++表示先赋值后运算,++a表示先运算后赋值

按位取反,简单来说就是数字加1,得到的结果正数变复数,负数变正数

左移是以二进制数进行计算,3的二进制数为11,左移表示右侧补一位变成二进制数110,结果为十进制数6

右移,7的二进制数为111,去掉右侧两位变成二进制数1,转换为十进制为1

按二进制位进行异或运算,相同为0,不同为1,3的二进制数为011,5的二进制数为101,异或运算后二进制数为110,转换为十进制数为6

按二进制位进行或运算,只要有一个1就为1,3的二进制数为011,5的二进制数为101,或运算后二进制数为111,转换为十进制数为7

按二进制位进行与运算,全为1结果就是1,3的二进制数为011,5的二进制数为101,与运算后二进制数为001,转换为十进制数为1

对于变量的使用方式

h.$[]数值运算

$[]其实和$(())的用法一致,特别是在使用一些较为复杂的综合算术运算时推荐使用$[]。详细示例可以参考下面的示例,请注意查看显示结果。
注意:算术运算涉及的数字及变量都必须是整数,不能为小数。

示例:
比较运算符的使用,运算结果为真则返回1,为假则返回0

2)环境变量

环境变量也称为全局变量,就是用户登录系统后预先设定好的变量,命名规则是以大写字母、数字和其他字符组成,不使用小写字母。系统中默认的内置环境变量是无法修改的,只有极少数自定义的环境变量是可以进行修改的。
环境变量一般都存放在系统的配置文件中,而配置文件针对用户而言分为全局配置文件和局部配置文件。其中,全局配置文件是/etc/profile文件,其内设置的环境变量针对所有用户都生效;局部配置文件是位于用户宿主目录下的~/.bash_profile文件,其内设置的环境变量只针对该用户生效。

#查看环境变量
可以使用set命令查看所有环境变量,也可以使用专属查看环境变量的命令env和printenv。

#常用内置环境变量说明
系统中内置的环境变量都是系统已经设定好的,用户无法修改,部分自定义的环境变量是根据用户的设定变化的,下面对一些较为常用的内置环境变量进行说明。

·$USER和$LOGANME:当前登录的用户名。
·$UID:当前登录用户的UID号。
·$SHELL:当前登录用户的默认Shell环境。
·$HOME:当前登录用户的宿主目录。
·$PWD:当前用户的工作路径。
·$HOSTNAME:当前计算机的计算机名。
·$LANG:查看系统默认的字符编码。
·$PS1:当前用户的主提示符(命令行提示符)。
·$PS2:当前用户的辅助提示符。
·$REPLY:如果read命令中未指定变量名,这个环境变量默认作为read命令的变量名。

示例:
输出当前用户名:

查看系统默认的字符集编码:

查看当前用户的主提示符(命令行提示符):

查看当前用户的辅助提示符:

#自定义环境变量
除了内置的环境变量,有时候也会自定义一些软件或服务所需要的环境变量,一般都是直接存放到配置文件中。如果需要临时定义,则可以使用下面代码中的三种方式,其在系统重启之后就失效了。

3)位置变量

位置变量是给脚本中的变量传递参数使用的,使用$1~$9表示,如果数字超过了两位就使用大括号{}将数字引用起来,例如第十个位置变量表示为“${10}”。

示例:
编写脚本a.sh,使用位置变量:

4)特殊变量

特殊变量也称为预定义变量,用户是无法创建或修改特殊变量的。常用的特殊变量如下:
·$?:返回命令执行的状态,若要判断上条命令是否执行成功可以使用“echo $?”,返回的状态值为0表示执行成功,非0表示执行失败。
·$#:表示位置参数的个数。
·$*:表示位置参数的传递内容。
·$$:表示当前进程的进程ID号。
·$0:表示当前执行进程的进程名。
·$!:表示最后一个后台进程的进程ID号。

示例:
使用预定义变量$?判断上一条命令是否执行成功,0表示执行成功,非0表示执行失败:

修改上节中编写的脚本a.sh,添加预定义变量$#和$*,执行后查看效果:

显示当前进程的ID号和进程号:

二、认识Shell脚本

Shell脚本是一个以.sh结尾的可执行文件,执行语句的顺序是连续自动执行多条Linux命令,直到所有命令执行完毕后才会结束,用于完成系统中一些较为复杂的管理任务。

1、Shell脚本格式

Shell脚本的第一行是以“#!”开头,后面紧跟Shell环境的绝对路径以及Shell名,指明当前Shell脚本的运行环境,其中注释行也是以“#”开头。最核心的组成部分是可执行的语句块,语句块由多条Linux命令组成,也可以是流程控制语句。创建和编辑Shell脚本直接使用vi命令即可。

1)Shell脚本中常用的符号说明

在编写Shell脚本时会用到管道符、定向符以及特殊的文件。
#设备文件说明
·/dev/null:黑洞文件,一般在脚本中为不显示输出信息,可以将信息直接输入该文件中,但是文件大小是不会变化的。
·/dev/stdin:标准输入文件,有时候以设备编号0替代。
·/dev/stdout:标准输出文件,有时候以设备编号1替代。
·/dev/stderr:标准错误输出文件,有时候以设备编号2替代。

#管道符及定向符文件说明
·|:管道符,将前面命令的结果作为后面命令的参数使用。
·>:覆盖重定向标准的正确输出,将正确执行命令的结果直接写入指定文件,不在屏幕上显示,文件存在内容则直接覆盖。
·>>:追加重定向标准的正确输出,将正确执行命令的结果直接写入指定文件,不在屏幕上显示,文件存在内容则在文件尾部追加。
·2>:覆盖重定向标准的错误输出,和>相反,是将错误执行命令的结果写入文件中。
·2>>:追加重定向标准的错误输出,和>>相反,是将错误执行命令的结果写入文件中。
·&>:标准正确和错误输出,无论命令是否执行成功都会将结果写入文件中,不会在屏幕上显示。

示例:
将错误执行命令的结果写入/home/a.txt文件中,使用1>命令执行的结果会在屏幕上输出但不会写入文件,使用2>命令执行的结果直接写入文件,屏幕上没有输出

在脚本中最常用的一种,无论命令是否执行成功都不在终端上输出,标准输出和标准错误将结果写入文件 /dev/null中,其中、dev/null可理解为黑洞文件,输出再多数据文件也不会变化。这样也不会占用太多磁盘空间。
注意:1>&2表示把标准输出重定向到标准错误输出,2>&1表示把标准错误输出重定向到标准输出。

2)Shell脚本的编写

下面使用vi或vim编辑器编写一个简单的脚本文件,实现输出“Hello,world”语句,脚本文件名可根据实际情况定义。

编写脚本文件b.sh,这里统一将脚本文件放入/home/sh目录中,脚本中的内容就输出“Hello world”这句话

2、Shell脚本的运行方式

Shell脚本的执行方式有5种,下面分别说明。
·使用Shell解释器,根据当前默认的Shell环境使用bash或sh命令执行脚本文件,在命令和脚本文件之间要存在一个空格。
·使用命令source加脚本文件执行,命令与脚本文件之间需加空格。
·使用符号“.”加脚本文件执行,符号与脚本文件之间需加空格。
·使用符号“./”加脚本文件执行,符号与脚本文件之间无须加空格,但是一定要赋予脚本文件可执行权限x才可以执行。
下面将编写的脚本文件b.sh按照上述5种方式运行。

3、Shell脚本简单示例

前面学习了Shell的变量、Shell脚本文件的编写及执行方式,下面将以两个简单的示例进行演示。
示例1:使用Shell模拟整数计算器
通过编写一个Shell脚本,通过控制输入数字和算术运算符实现简单的加减乘除取模运算,模拟一个简单的整数计算器功能。
这里编写脚本时使用的是标准格式expr,注意对于逻辑运算符必须使用双引号引用,否则在使用乘法“*”时会报错,也可以使用$(())或$[]实现。

#!/bin/bashread -p "please enter the first number:" x #定义第一个变量x,输入第一个整数read -p "please enter the second number:" y #定义第二个变量y,输入第二个整数read -p "please enter logical operator:" z #定义第三个变量z,输入算术运算符result=`expr "$x" "$z" "$y"` #算术表达式,定义变量resultecho $result

执行结果:

示例2:使用Shell求出两个日期之间的天数差
编写脚本从控制台输入两个格式为“YYYY-MM-DD”的日期,日期最好是一个大日期一个小日期,然后计算这两个日期之间相差多少天。
实现思路就是通过date命令计算出指定日期到“1970-01-01 00:00:00”经过了多少秒,然后计算出两个日期的秒数差得出天数,为防止出现负数,我们使用大日期的秒数减去小日期的秒数。

#!/bin/bashread -p "please input small date (YYYY-MM-DD) :" x #定义一个变量,指定小日期read -p "please input big date (YYYY-MM-DD) :" y #定义一个变量,指定大日期m=`date +%s -d "$x"` #计算出小日期到1970-01-01 00:00:00经过了多少秒n=`date +%s -d "$y"` #计算出大日期到1970-01-01 00:00:00经过了多少秒z=`expr $n - $m` #两个日期的秒数差day=`expr $z / 86400` #一天是86400秒,求出天数echo "day of $day"

执行结果:

三、流程控制语句

1、条件测试表达式

进行条件判断有两种格式,第一种是使用test命令,第二种是使用中括号的方式,括号两端必须存在空格。命令“echo $?”执行返回的状态值为0表示表达式为真(成功),非0表示为假(失败)。格式如下:
test 条件表达式
[ 条件表达式 ]
常用的判断条件包括文件状态比较、整数数值比较、字符串比较和逻辑测试,下面介绍4种判断条件的使用。

1)文件状态比较

文件状态比较就是判断这个文件是目录还是普通文件,或文件权限为可读、可写或可执行等。文件状态比较的格式如下:
test 操作符 文件或目录
[ 操作符 文件或目录]
.-b:判断是否为块状设备文件
.-c:判断是否为字符设备文件
.-d:判断是否为目录
.-e:判断文件或目录是否存在
.-f:判断是否为普通文件
.-L/-h:判断是否为软链接文件
.-r:判断是否有读取权限
.-w:判断是否有写入权限
.-x:判断是否有可执行权限
.-s:判断文件是否存在且大小大于0

示例:
判断/etc/hosts文件是否存在,返回值为0表示文件存在

判断/etc/hosts是文件还是目录,返回值为非0表示这是一个文件而不是目录

判断文件/etc/hosts的大小是否大于0,返回值为0表示大于0

2)整数值比较

在条件表达式中对整数值进行比较不能采用“>”等算术运算符,而是需要使用操作符,格式如下:
test 整数值 操作符 整数值
[ 整数值 操作符 整数值 ]
操作符说明如下:
·-eq:等于(Equal)。
·-ne:不等于(Not Equal)。
·-gt:大于(Greater Than)。
·-lt:小于(Lesser Than)。
·-le:小于或等于(Lesser or Equal)。
·-ge:大于或等于(Greater or Equal)。

示例:
测试100是否大于20,使用连接符号&&表示当前的命令或结果执行成功,后面的命令才会执行,如果后面的输出语句输出就表示前面的命令执行成功

统计根分区的使用率,如果使用率超过80%就输出一句警告信息“disk will be full”,此时系统的根分区是/dev/sda3,只能比较整数值,所有需要将百分号前的整数值截取出来,没有输出就表示使用率没有超过80%

3)字符串比较

条件判断中的字符串比较除了相同和不相同,还可以判断是否为空,字符串在比较时最好使用双引号(“”)。格式如下:
[ “字符串1” 操作符 “字符串2” ]
[ 操作符 “字符串” ]
操作符说明如下:
·=:字符串内容相同。
·!=:字符串内容不同,!表示相反的意思。
·-z:字符串内容为空。
·-n:字符串内容不为空。

示例:
判断两个字符是否相同,返回值为0表示相同,返回值为非0表示不同

判断字符串为空,使用操作符-z进行判断,返回值为0表示为空;判断字符串不为空,使用操作符-n进行判断,返回值为0表示不为空,返回值为非0,表示为空。

查看当前工作路径是否为/home,如果不是就输出当前工作路径,这里使用连接符“||”表示前面执行失败时后面命令才会执行,借助环境变量PWD实现。如下,当前工作目录是/root,不是/home

4)逻辑测试

逻辑测试就是判断条件表达式中两个或多个表达式是否同时成立或者有一个条件成立,也就是说逻辑测试是对表达式的逻辑结果(真或假)进行判断。格式如下:
[ 表达式1 ] 逻辑测试符 [ 表达式2 ]
常用的逻辑测试符如下:
·&&:逻辑与,前后表达式全部成立时整个测试结果才为真,也可以使用“-a”表示,就是and(而且)的意思。
·||:逻辑或,前后表达式只要有一个成立则整个测试结果就为真,也可以使用“-o”表示,就是or(或者)的意思。
·!:逻辑否,对整个表达式的结果取反,即逻辑真变为逻辑假,逻辑假变为逻辑真。

示例:
使用逻辑与判断前后表达式是否为真,同时为真时整体测试结果才为真。
使用中括号[]和符号“&&”的写法

使用“-a”的写法

改成test的写法,注意看格式

使用逻辑否对表达式的测试结果取反,表达式本来为真,逻辑否后就变为假,注意空格

2、if判断语句

在Shell脚本中语句通常都是按照顺序依次执行,但是有些时候还需要根据条件来选择执行某一部分语句,这个时候就需要使用到if判断语句,相当于汉语中的“如果……就……”。if判断语句主要分为三种,即单条件if语句、双条件if语句和多条件if语句。

1)单条件if语句

这是if语句中最简单的一种判断,对指定的条件测试表达式进行判断,当条件成立为真时,才会执行then后面的语句块,然后进入fi结束判断;否则直接进入fi结束判断。语法格式如下:
if 条件表达式
then
语句块
fi

示例
编写脚本e.sh,判断/home目录下是否存在a.txt文件,如果存在就删除该文件,脚本内容如下:

#!/bin/bashif test -e /home/a.txtthenrm -rf /home/a.txtfi

如果需要将if和then放在同一行,只需要在then前面添加分号“;”即可,格式如下

#!/bin/bashif [ -e /home/a.txt ];thenrm -rf /home/a.txtfi

2)双条件if语句

双条件if语句使用“if…else…”表示,意思就是“如果……那么……否则……”,当条件表达式成立,那么执行语句块1,进入fi结束判断;否则就是条件表达式不成立,执行语句块2,也进入fi结束判断。语法格式如下:
if 条件表达式
then
语句块1
else
语句块2
fi

示例:
编写脚本f.sh,实现从控制台输入一个整数,判断是偶数还是奇数。实现原理就是除以2取余数,余数为1就是奇数,余数为0就是偶数

#!/bin/bashread -p "please enter a number:" x #定义变量x,从控制台赋值if [ `expr $x % 2` -eq 0 ] #该数除以2取余,判断是否等于0#if((x%2==0)) #实现的第二种方式,非标准写法thenecho "$x is odd number!" #条件为真就执行输出为偶数elseecho "$x is even number!" #条件为假就执行输出为奇数fi

执行结果:

3)多条件if语句

多条件就是存在多种条件,相当于是在if中嵌套使用if判断,使用的是“if…elif…elif…else”,会依次判断多个条件执行对应的语句块,直到最后判断结束进入fi。语法格式如下:
if 条件表达式1
then
语句块1
elif 条件表达式2
then
语句块2
else
语句块3
fi
这里只使用三个条件进行结构说明,其实也可以在else前面存在多个elif进行条件判断。

示例
从控制台输入两个整数进行比较,这里采用的非标准写法,直接使用的(())

#!/bin/bashread -p "input the first number:" xread -p "input the second number:" yif((x==y))thenecho "$x is equal $y!"elif((x>y))thenecho "$x is granter than $y!"elseecho "$x is lesser than $y!"fi

执行结果:

3、循环语句

在编写一些复杂的Shell脚本时,除了使用条件判断,有时候还需要重复执行某些语句,这个时候就需要使用到循环语句,它是在一定条件下重复执行语句的流程结构。循环语句主要由循环体和循环体终止两部分组成,在Shell脚本中循环语句有for循环、while循环以及until循环,本节将分别介绍这几个循环语句的使用方法。

1)for循环语句

for循环语句就是为变量设定一组取值列表,变量每次读取列表中不同的变量值,直到所有值读取完就退出循环。for循环标准的语法格式如下:
for 变量名 in 取值列表
do
循环体
done
其中取值列表的写法有多种,取值列表间可以使用空格隔开,也可以使用{初始值…结束值}等多种方式表示,具体可以参考下面的示例说明。而“do…done”也可以使用大括号{}来表示。

示例:
编写Shell脚本i.sh,循环输出10个自然数1~10

#!/bin/bash#for i in 1 2 3 4 5 6 7 8 9 10 #方法1:取值列表间使用空格隔开#for i in {1,2,3,4,5,6,7.8.9.10} #方法2:使用大括号,取值列表间用逗号隔开#for i in {1..10} #方法3:使用范围1..10,需使用大括号#for i in `seq 1 10` #方法4:使用seq关键字加初始值和结束值#for i in `seq 10` #方法5:使用seq关键字加结束值,因为默认初始值为1可省略for((i=1;i<=10;i++)) #方法6:使用布尔表达式#do{#将do开始使用左大括号{替代echo $i}#将done结束使用右大括号}替代#done

执行结果:

编写Shell脚本j.sh,打印出九九乘法表,其中echo的用法使用了“-ne”选项和制表符“\t”

#!bin/bashfor((i=1;i<=9;i++)){for((j=1;j<=i;j++)){echo -ne "$i*$j=$[i*j]\t"}echo}

执行结果:
将九九乘法表进一步扩展,将输出的字体显示为紫色,重命名脚本文件为j2.sh,仅供学习

#!bin/bashfor((i=1;i<=9;i++)){for((j=1;j<=i;j++)){echo -ne "\033[1;35m$i*$j=$[i*j]\t\033[0m"}echo}

执行结果:

2)while循环语句

while循环是根据特定的条件重复执行命令,当条件表达式为真时,“do done”中的循环体语句会一直执行,当表达式为假时进入done结束循环体,其中条件表达式可以使用标准的测试表达式写法,也可以使用双小括号(())。而“do … done”则不能使用大括号{…}替代。语法格式如下:
while 条件表达式
do
循环体
done

示例:
编写Shell脚本k.sh,求出1~10这10个数之和,结果为55,通过Shell标准语法实现

#!/bin/bashi=0 #定义变量,控制循环次数sum=0 #定义变量,接收所有数的总和#while [ $i -lt 10 ] #判断条件小于10就一直执行循环体中的语句while((i<10)) #另一种写法do# let i++ #自增运算,增长值为1#i=$[i+1] #另一种写法i=$((i+1)) #另一种写法# sum=$((sum+i)) #计算所有数的总和#sum=$[sum+i]sum=`expr $sum + $i` #另一种写法doneecho $sum

执行结果:

3)until循环语句

和while循环刚好相反,until循环是条件表达式中的条件为假时才会执行“do done”循环体中的语句,直到条件为真也就是条件成立时进入done结束循环体。语法格式如下:
until 条件表达式
do
循环体
done

示例:
编写脚本l.sh,求出1~10中的奇数之和与偶数之和,在循环体中通过if双条件判断语句实现

#!/bin/bashi=0sum1=0 #定义偶数之和的变量sum1sum2=0 #定义奇数之和的变量sum2until test $i -ge 10dolet i++if [ `expr $i % 2` -eq 0 ] #判断余数是否等于0,为0就表示偶数thensum1=`expr $sum1 + $i` #偶数相加elsesum2=`expr $sum2 + $i` #奇数相加fidoneecho "the sum of even number is $sum1!" #输出偶数之和echo "the sum of odd number is $sum2!" #输出奇数之和

执行结果:

4、循环控制语句

循环控制就是根据判断结果决定循环体中语句执行的次数,在Shell中循环控制可以通过break、continue以及对执行的循环体进行控制。下面将分别对这三种语句进行讲解说明。

1)break语句

在for、while、until等循环语句中,break的意思就是“中断”,当满足条件时就中断循环体,用于跳出当前所在的循环体,执行循环体外的语句,如果有多层循环,默认结束当前循环体的循环语句,Shell脚本不会退出。

示例:
编写脚本break.sh,输出1~10十个自然数,当输出到5时结束整个循环体,在最后输出test是为方便测试,表示break只是结束了循环体,但是程序未结束

#!/bin/bashi=0while [ $i -lt 10 ]dolet i++echo $iif [ $i -eq 5 ]then breakfidoneecho "test"

执行结果:

编写脚本cfbbreak.sh,使用break结束两层循环

#!/bin/bashfor((i=1;i<=9;i++)){for((j=1;j<=i;j++)){echo -ne "\033[1;35m$i*$j=$[i*j]\t\033[0m"if(j==5)then break 2 #默认为1,表示跳出当前循环,2表示跳出两层循环fi}echo}

执行结果:

2)continue语句

在for、while、until等循环语句中,continue用于跳过循环体内余下的语句,重新判断条件以便执行下一次循环。

示例:
编写脚本continue.sh,输出1~10十个自然数,跳过输出5和8这两个数字

#!/bin/bashi=0until [ $i -gt 10 ]do((i++))if [ $i -eq 5 -o $i -eq 8 ]then continuefiecho $idone

执行结果:

3)exit语句

exit的意思就是“退出”,当满足条件时就结束整个循环体,也包括退出整个Shell脚本程序,这一点和break是有区别的。

示例:
编写Shell脚本exit.sh,输出1~10十个自然数,当输出到5时就结束整个Shell脚本,不仅仅是结束循环体。可以和break语句对比看效果,最后的test语句是不会输出的

#!/bin/bashi=0while [ $i -lt 10 ]doi=`expr $i + 1`echo $iif [ $i -eq 5 ]then exitfidoneecho "test"

执行结果:

5、选择语句

循环语句是根据固定的顺序依次执行语句,某些时候需要根据测试条件的结果去决定需要执行的语句,改变固定的执行顺序,增加程序的灵活性,此时就需要使用到选择语句。在Shell脚本中常用的选择语句有case多重分支语句和select选择语句。

1)case多重分支语句

case语句相当于一个条件判断的多分支结构,是根据case后面的变量值逐步和下面的取值1、取值2进行比较,如果值刚好匹配就执行该取值下的语句,每个语句后面使用双分号“;;”表示结束,最后跳转到esac结束。最后的“*”表示以上取值和变量值都无法匹配时就执行下面的语句。语法格式如下:
case 变量值 in
取值1)
语句块1
;;
取值2)
语句块2
;;
……
*)
语句块n
;;
esac

示例:
编写脚本case.sh,从控制台输入一个字符,判断是单个数字还是单个字母(不区分大小写),如果输入的是多个字符或其他就提示“Unkonown!”

#/bin/bashread -p "please enter a char:" strcase $str in[0-9])echo "This is a digit!";;[a-z]|[A-Z])echo "This is a letter!";;*)echo "Unknown!"esac

执行结果:

2)select选择语句

select语句的主要作用就是创建菜单,在执行带select循环语句的脚本时,输出会按照数字顺序的列表显示一个菜单项,并显示提示符(默认是“#?”),同时等待用户输入数字进行选择。语法格式如下:
select 变量名 in 菜单取值列表
do
执行命令语句块
done

示例:
编写一个脚本select.sh,实现select语句的简单功能

#!/bin/bashselect name in Jack Amy Marydoecho $namedone

执行结果:

通过上面的示例可以看到select语句执行后默认的提示符是“#?”,提示用户输入菜单序号。使用内置的环境变量PS3作为提示符(默认值为“#?”)时,可以对PS3的值进行修改,使用环境变量REPLY获取select选择项对应的数字序号,退出时可以使用组合键Ctrl+C或Ctrl+D。将上述示例进行优化,结果如下:
优化后的脚本名为select1.sh

#!/bin/bashPS3="please enter number of menu:"select name in Jack Amy Marydoecho "$REPLY)" $namedone

执行结果:

3)case和select语句的结合使用

case和select语句一般都是一起使用。注意,如果要在脚本中使用中文,可以在图形化界面或者通过远程终端工具连接Linux系统实现,在字符界面是无法使用中文的。下面以一个简单的示例进行说明。
编写一个脚本文件select2.sh,实现控制MySQL数据库的服务状态,执行脚本后屏幕上会显示一
个类似于菜单选项的画面,根据菜单选项对应的数字,对MySQL数据库服务状态进行控制。例如,
①启动服务,②停止服务,③重启服务,④查看服务状态,⑤退出。如果输入的数字或内容错误,
则会提示“选择错误,请重试!”。脚本中的输出内容这里以英文表示,不一定标准

#!/bin/bashPS3="please slect number for menu:"select a in start stop restart status quitdocase $a instart)echo "$REPLY) Service started"systemctl start mysqld.serviceexit;;stop)echo "$REPLY) Service stoped"systemctl stop mysqld.serviceexit;;restart)echo "$REPLY) Service stoped"systemctl restart mysqld.serviceexit;;status)echo "$REPLY) Service stoped"systemctl status mysqld.serviceexit;;quit)exit;;

四、Shell函数

当在编写Shell脚本时发现某个语句块需要重复使用,这个时候可以将需要重复使用的语句编写成函数,在要使用的时候便可以直接调取。简单来说,Shell中的函数就是一段预先编译好的脚本,作用是简化代码、提高程序的执行效率。

1、函数的定义和调用

在使用函数前首先需要使用关键字function定义函数。函数定义的格式有两种,一种是标准写法,一种是简化写法。

标准写法格式如下:
function 函数名(){
函数体
}
函数名
简化写法格式如下:
函数名(){
函数体
}
函数名

下面编写一个名为hellofun.sh简单的函数

#!/bin/bashfunction hello() {echo "Hello,world!"}test() {echo "test function"}hellotest

执行结果:

2、向函数传递参数

在Linux Shell编程中,向函数传递参数是以位置参数的方式传递的。

下面编写一个带参数的函数,借助位置变量$1~$9。另外,函数中的$@或$*表示函数中的所有参数。
编写一个名为sumfun.sh的脚本

#!/bin/bashsum() {echo $(($1+$2+$3))}sum $1 $2 $3 #或sum $@ 或 sum $*

执行结果:

3、函数返回值

有时候需要脚本执行完成后返回特定的值来完成脚本的后续操作,这些特定的值就是函数返回值。在Linux Shell编程中,函数通过return返回其退出状态,0表示无错误,1表示有错误。在脚本中可以有选择地使用return语句,因为函数在执行完最后一条语句后将执行调用该函数的地方执行后续操作。

示例:
编写一个名为return.sh的脚本

#!/bin/bash#使用return语句的函数show_week(){echo -n "What you input is:"echo "$1"#根据输入的参数值来显示不同的操作case $1 in0)echo "Today is Sunday."return 0;;1)echo "Today is Monday."return 0;;2) echo "Today is Tuesday."return 0;;3)echo "Today is Wednesday."return 0;;4) echo "Today is Thursday."return 0;;5)echo "Today is Friday."return 0;;6)echo "Today is Saturday."return 0;;*)return 1;;esac} #主程序部分根据返回值不同输出不同的结果if show_week "$1" #在if中调用函数thenecho "What you input is right!" #提示参数输入正确elsefiecho "What you input is wrong!" #提示参数输入错误exit()

执行结果:

4、函数调用

在Linux Shell脚本中可以同时放置多个函数,函数之间允许相互调用,而且允许一个函数调用多个函数。

1)脚本放置多个函数

可以在脚本中放置多个函数,脚本执行时按照调用函数的顺序执行这些函数。

示例:
编写一个名为functioncall1.sh的脚本

#!/bin/bash#该函数在一行中显示周一到周日show_week(){for day in Monday Tuesday Wednesday Thursday Friday Saturday Sundaydoecho -n "$day"done}#该函数在一行中显示1~7show_number(){for((integer = 1;integer <=7;integer++))doecho -n "$integer"done}#该函数用于显示1~7的平方show_square(){i=0until [[ "$i" -gt 7 ]] #通过until实现1~7的平方运算和结果输出dolet "square=i*i"echo "$i * $i = $square"let "i++"done}#顺序执行函数show_weekshow_numbershow_square

运行结果:

2)函数相互调用

在Linux Shell编程中,函数之间可以相互调用,调用时会停止当前运行的函数转去运行被调用的函数,直到调用的函数运行完,再返回当前函数继续运行。

示例:
编写一个名为functioncall2.sh的脚本

#!/bin/bash#函数执行显示输入参数的平方square(){echo "Please input the num: "read num1let "squ=num1*num1"echo "Square of $num1 is $squ. "}#函数执行显示输入参数的立方cube(){echo "Please input the num: "read num2let "c=num2*num2*num2"echo "Cube of $num2 is $c. "}#函数执行显示输入参数的幂次方power(){echo "Please input the num: "read num3echo "Please input the power: "read plet "temp = 1"for (( i=1; i <= $p; i++ ))dolet "temp=temp*num3"doneecho "power $p of $num3 is $temp. "}#选择调用的函数choice(){echo "Please input the choice of operate(s for square; c for cube and p for power): "read char#判断输入的参数是哪个,然后根据输入的不同执行不同的函数case $char ins)square;; #执行平方函数c)cube;; #执行立方函数p)power;; #执行幂运算*)echo "What you input is wrong! ";;esac}#调用函数choicechoice

运行结果:

3)一个函数调用多个函数

在Linux Shell编程中,允许一个函数调用多个函数,在该函数调用其他函数时同样需要按照调用的顺序来执行调用的函数。

示例:
编写一个名为functioncall3.sh的脚本

#!/bin/bash#该函数实现显示整数位数count_of_int(){if [ $1 -gt 9999 ] #当该数的值大于9999时,表示该数为5位数thenlet "place=5"elif [ $1 -gt 999 ]#当该数大于999而小于9999时,表示该数为4位数thenlet "place=4"elif [ $1 -gt 99 ] #当该数大于99而小于999时,表示该数为3位数thenlet "place=3"elif [ $1 -gt 9 ]#当该数大于9而小于99时,表示,该数为2位数thenlet "place=2"else#当该数为大于等于0而小于等于9时,表示该数为1位数let "place=1"fiecho "The place of the $1 is $place."#输出该数的位数}#该函数实现显示该整数每个数位上的数字num_of_int(){let "ten_thousand = $1/10000"let "thousand =$1/1000%10"let "hundred = $1/100%10"let "ten = $1%100/10"let "inp = $1%10"#当输入万位上的数不等于0时,表示该数为5位数,需输出万、千、百、十、个位if [ $ten_thousand -ne 0 ]thenecho "$ten_thousand$thousand$hundred$ten$inp"#当输入万位上的数等于0时而千位不等于0,表示该数为4位数,需输出千、百、十、个位elif [ $thousand -ne 0 ]thenecho "$thousand$hundred$ten$inp"#当输入万位和千位的数等于0时而百位不等于0,表示该数为3位数,需输出百、十、个位elif [ $hundred -ne 0 ]thenecho "$hundred$ten$inp"#当输入万、千和百位的数等于0时而十位不等于0,表示该数为2位数,需输出十、个位elif [ $ten -ne 0 ]thenecho "$ten$inp"#其他状态时输出个位数elseecho "$inp"fi}#调用函数count_of_int和num_of_intshow(){echo "Please input the number(1-99999): "read numcount_of_int $num#显示输入参数的位数num_of_int $num#显示输入参数的各数位值}#脚本中调用函数show

运行结果:

5、局部变量和全局变量

在Linux Shell 编程中,可以通过local关键字在Shell函数中声明局部变量,局部变量将局限在函数范围内。此外,函数也可以调用函数外的全局变量,如果一个局部变量和一个全局变量的名字相同,则在函数中局部变量将覆盖掉全局变量。

#!/bin/bashtext="global variable"#函数中使用的局部变量和全局变量的名字相同use_local_var_fun(){local text="local variable"echo "In function use_local_var_fun "echo $text}#输出函数use_local_var_fun内的局部变量值echo "Execute the function use_local_var_fun"use_local_var_fun#输出函数use_local_var_fun外的全局变量值echo "Out of function use_local_var_fun"echo $textexit 0

运行结果:

需要做网站?需要网络推广?欢迎咨询客户经理 13272073477