《Linux基础》09. Shell 编程
本文以 CentOS 7.6 为例。
1:Shell 简介
Shell 是一个命令行解释器,它为用户提供了一个向 Linux 内核发送请求以便运行程序的界面系统级程序,用户可以用 Shell 来执行命令,它接收应用程序或用户的命令,然后调用操作系统内核执行。
2:Shell 脚本
shell 脚本 本质是一个文件,保存特定格式的指令。
只需使用任意文本编辑器,按照语法编写相应程序,即可在安装 shell 命令解释器的环境下执行。
2.1:规则&语法
- 脚本开头添加以下语句:
1 | !/bin/bash |
“
#!
” 用来声明脚本由什么 shell 解释,否则使用默认 shell
- 单个 “ # ” 号代表注释当前行。
1 | 这是注释 |
- 多行注释的写法:
1 | :<<! |
- 脚本文件一般以 “ .sh ” 为后缀名。
- 不要轻易加缩进(空格、tab)。
- 单引号与双引号的作用略有区别。
- 使用反引号【`】引用命令,则可以运行里面的命令并把结果返回。
- 【$】符号的使用,可与反引号【`】效果相同。
2.2:执行方式
执行 shell 脚本有三种方式:
- 方式一:
直接输入脚本的相对路径或绝对路径。(需授予脚本文件可执行权限 “ +x ”)
- 方式二:
以 sh
或 bash
命令加上脚本相对路径或绝对路径。(脚本文件不需要可执行权限)
- 方式三:
以 .
或 source
命令加上脚本相对路径或绝对路径。(脚本文件不需要可执行权限)
第三种方式不同于前两种,前两种方式运行时会嵌套子shell;第三种方式不会嵌套,就在本环境运行。
嵌套子 shell 与不嵌套子 shell 的区别:环境变量的继承关系。如在子 shell 中设置的当前变量,父 shell 中是不可见的。
2.3:第一个 Shell 脚本
创建一个脚本,输出 “ hello world! ”。
1 | !/bin/bash |
3:变量
Linux 中 Shell 变量有系统变量和用户自定义变量。
除此以外还有位置参数变量与预定义变量。在后面会介绍。
3.1:系统变量
系统变量也可以叫做环境变量。一般是指在操作系统中用来指定操作系统运行环境的一些参数。
环境变量有:
1 | HOME、$PWD、$SHELL、$USER ... |
查看某个系统变量:echo $HOME
显示所有系统变量:set
3.2:用户自定义变量
3.2.1:规则
- 变量名称可以由字母、数字和下划线组成,但是不能以数字开头。
- 等号两侧不能有空格。
- 变量名称一般习惯为大写,这是一个规范,遵守即可。
- 使用变量时要加上 “ $ ”。
3.2.2:基本语法
定义变量:
1 | 变量名=值 |
撤销变量:(即销毁某个变量)
1 | unset 变量名 |
静态变量声明:
1 | readonly 变量名=值 |
静态变量不能撤销,为只读。
3.2.3:示例
示例脚本如下:
1 | !/bin/bash |
3.3:自定义环境变量
用户可以在 /etc/profile 文件中自定义环境变量,以方便不同的脚本使用同一个变量。
方法,在 /etc/profile 添加以下语句:
1 | 自定义一个变量 |
保存后在命令行执行以下命令使定义生效:source /etc/profile
不要轻易修改系统默认环境变量,以免出错。
示例,自定义 TOMCAT_HOME 环境变量,值为 opt/tomcat:
1 | 使用 vi 编辑器编辑 /etc/profile 文件 |
4:位置参数变量
如果想在执行 shell 脚本时传入参数,可以在执行脚本时直接在后面跟上数据,以空格分割,使用位置参数变量来接收。
4.1:语法
1 | =========================================================================== |
4.2:示例
编写以下脚本,并在执行时传参。
1 | !/bin/bash |
执行以下命令:
1 | bash position.sh 250 hello |
结果:
如果要在脚本执行时读取控制台输入,可以使用 read。
5:预定义变量
shell 设计者事先已经定义好的变量,可以直接在 shell 脚本中使用。
5.1:语法
1 | =========================================================================== |
5.2:示例
编写以下脚本,该脚本会调用 【4.2:示例】 中的脚本。
1 | !/bin/bash |
结果:
6:读取标准输入
读取标准输入,即读取控制台输入。可使用 read。
基本语法:
1 | read 可选选项 变量 |
常用选项:
参数 | 说明 |
---|---|
-p |
指定读取值时的提示字符串。 |
-t |
指定读取值时等待的时间(秒)。 |
示例:
1 | !/bin/bash |
7:运算符
shell 中提供三种方式进行各种运算操作。
- 方式一
1 | ((运算式)) |
- 方式二
1 | [运算式] |
- 方式三
1 | expr 运算式 |
1 | 方式三(expression)使用注意事项: |
示例脚本:
1 | !/bin/bash |
结果:
8:条件判断
Shell 编程中判断条件真伪。
基本语法:
1 | [ 条件 ] |
8.1:基本判断
数值或字符串之间的判断。注意正确使用空格。
语法 | 判断说明 |
---|---|
-eq |
两数比较,相等(equal) |
-ne |
两数比较,不相等(not equal) |
-gt |
两数比较,大于(greater than) |
-lt |
两数比较,小于(less than) |
-ge |
两数比较,大于等于(greater equal) |
-le |
两数比较,小于等于(less equal) |
= |
两字符串比较,相等 |
!= |
两字符串比较,不相等 |
8.2:文件权限判断
对文件权限的判断。使用绝对路径或相对路径来标明文件。
语法 | 判断说明 |
---|---|
-r |
文件判断,有可读权限(read) |
-w |
文件判断,有可写权限(write) |
-x |
文件判断,有可执行权限(execute) |
8.3:文件类型判断
对文件类型的判断。使用绝对路径或相对路径来标明文件。
语法 | 判断说明 |
---|---|
-e |
文件存在(existence) |
-f |
文件存在且是一个常规文件(file) |
-d |
文件存在且是一个目录(directory) |
8.4:多条件判断
多重条件判断:
语法 | 判断说明 |
---|---|
-a |
两个条件同时成立。 |
-o |
两个条件只需成立一个。 |
命令控制执行:
1 | ========================================= |
8.5:示例
该示例中会用到简单的 if 流程控制语句。在之后介绍。
1 | !/bin/bash |
运行结果:
9:流程控制
流程控制语句主要有:
- if
- case
- for
- while
- until
- break
- continue
shell 脚本 break 与 continue 的使用与高级编程语言类似,这里就不详细介绍了。
9.1:if 判断
- 单分支判断:
1 | if [ 条件 ] |
也可以用以下写法:(【;】表示一行实现2步命令的分割)
1 | if [ 条件 ];then |
- 多分支判断:
1 | if [ 条件 ] |
elif 语句可随意增减。
示例:
1 | !/bin/bash |
9.2:case 判断
语法:
1 | case 变量 in |
可随意添加分支。
;;
相当于 break 。*)
相当于 default 。
示例:
1 | !/bin/bash |
9.3:for 循环
for 循环有两种使用方式。
9.3.1:语法
- 方式一
1 | for (( 初始变量; 循环控制条件; 变量变化 )) |
- 方式二
1 | for 变量 in 值1 值2 值3 |
9.3.2:示例
1 | !/bin/bash |
执行:
1 | bash forDemo.sh 1 2 3 4 |
9.4:while 循环
当条件成立时进入循环,直到条件不成立时才退出循环。
语法:
1 | while [ 条件判断式 ] |
示例:
1 | !/bin/bash |
9.5:until 循环
until 与 while 相反,当条件成立时退出循环。
语法:
1 | until [ 条件判断式 ] |
10:函数
shell 编程和其它编程语言一样,有系统函数,也可以自定义函数。
函数调用有两种方式:
- 方式一
1 | (函数名 参数1 参数2) |
- 方式二
1 | 函数名 参数1 参数2 |
10.1:自定义函数
10.1.1:介绍
函数定义有两种格式。
1 | 格式一 |
函数规则:
- 调用函数之前必须先定义函数。建议将函数放在代码前面。
- 函数中接收传入的参数可使用位置参数变量。使用规则相似。
- 函数返回值,可通过
$?
系统变量获得,也可赋给某个变量。 - 可以加 return 提前结束并带回返回值,范围 0~255。一般规则如下:
return
:用最后命令的执行状态决定返回值return 0
:无错误返回return 1
:有错误返回
- 如果不加 return,将以最后一条命令运行结果作为返回值。
10.1.2:示例
1 | !/bin/bash |
10.2:系统函数
系统自带的函数。
这里只介绍两个系统函数。
以下两个函数都可在命令行中直接执行并看到结果。
basename()函数
功能:返回完整路径最后 “ / ” 的部分,常用于获取文件名。
参数:
- pathname:绝对路径
- suffix:后缀,如果suffix被指定了,basename会将文件名中的suffix去掉。
示例:
1 | basename /home/aaa/bbb/test.txt |
运行结果:
dirname()函数
功能:返回完整路径最后 “ / ” 的前面的部分,常用于获取路径。
参数:
- dirname:绝对路径
示例:
1 | dirname /home/aaa/bbb/test.txt |
运行结果:
11:文件包含
和其他语言一样,shell 脚本也可以引用外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件。
语法格式:
- 方式一:
1 | . 文件名 |
- 方式二:
1 | source 文件名 |
两个脚本不在同一目录时,要用绝对路径。
被包含的文件不需要可执行权限。
简单起见,通常用第一种方式。
示例:
inMain.sh 文件:
1 | !/bin/bash |
inTest.sh 文件:
1 | !/bin/bash |
运行结果:
是非入耳君须忍,半作痴呆半作聋。
——《警世》(明)唐寅