认识shell
一、
shell
基础
1
、
shell
概念
shell
英文翻译过来是外壳的意思,作为计算机语言来理解可以认为它是 操作系统的外壳。可以通过shell
命令来操作和控制操作系统,比如 Linux中的
shell
命令就包括
ls
、
cd
、
pwd
等等。
shell
在内核的基础上编写的一个应用程序,它连接了用户和
Linux
内 核,从而让用户能够更加便捷、高效、安全的使用 linux
内核,这其实 就是 shell
的本质。
使用专业术语的说法来解释,
Shell
其实是一个命令解释器,它通过接 受用户输入的 Shell
命令来启动、暂停、停止程序的运行或对计算机进 行控制。
2
、
shell
脚本
shell
脚本就是由
Shell
命令组成的执行文件,将一些命令整合到一个文件 中,进行处理业务逻辑,脚本不用编译即可运行,它从一定程度上减轻 了工作量,提高了工作效率,还可以批量、定时处理主机,方便管理员 进行设置或者管理。
3
、
shell
脚本编写注意事项
shell
命名
: shell
脚本名称命名一般为英文、大写、小写、后缀以
.sh
结尾
不能使用特殊符号、空格
名称要写的一眼可以看出功能,也就是顾名思义 shell脚本首行需要
#!/bin/bash
开头
shell
脚本变量
不能以数字、特殊符号开头
,可以使用下划线
_
,但不能 用破折号——
二、
shell
脚本的构成
脚本声明
注释信息
可执行语句
三、编写
shell
脚本
1
、伟大编程项目
——Hello World
'Hello,World!'
中文意思是
“
你好,世界
”
。因为
The C Programming Language 中使用它做为第一个演示程序,后来的程序员在学习编程或 进行设备调试时延续了这一习惯。
执行
shell
脚本的几种
bash
脚本名称
source
脚本名
在当前环境生效,其他方法都是在开一个
shell
进程
sh
脚本名称
添加
x
权限,
./
脚本名称
shell
脚本其实就是有序执行命令条件
[root@localhost ~]
# touch hello.sh
[root@localhost ~]
# vim hello.sh
#!/bin/bash
echo
"Hello World!"
#
输出
“Hello World
!
”
:wq
[root@localhost ~]
# bash hello.sh #
运
⾏
shell 脚本的⽅
法
1
Hello World!
[root@localhost ~]
# sh hello.sh #
运
⾏ shell脚本的
⽅
法
2
Hello World!
[root@localhost ~]
# chmod +x hello.sh #
运
⾏
shell
脚本 的⽅
法
3
[root@localhost ~]
# ll hello.sh
-rwxr-xr-x
.
1
root root
32 6
⽉
14 14
:22 hello.sh
[root@localhost ~]
# ./hello.sh
Hello World!
[root@localhost ~]
# source ./hello.sh #
只在当前环境生效, 其他方法是另外再开一个shell
。
Hello World!
[root@localhost ~]
# vim hello.sh #
修改
hello
脚本
#!/bin/bash
echo
"Hello World!"
ls
-lh
/
df
-hT
:wq
[root@localhost ~]
# sh hello.sh
Hello World!
2
、编写
nginx
安装脚本
1.
安装依赖环境
2.
下载
nginx
压缩包
3.
解压
4.make
和
make install
安装
5.
按照顺序执行指令
[root@localhost ~]
# vim /root/shell/install_nginx.sh
#!/bin/bash
yum
-y
install
gcc
gcc-c
++
make
pcre-devel openssl-devel
wget
cd
/usr/local/src/
wget
'http://nginx.org/download/nginx-1.22.1.tar.gz'
tar xf nginx-1.22.1.tar.gz
cd
nginx-1.22.1
./configure
--prefix
=
/usr/local/nginx
make
-j
4
make
install
:wq
#
逻辑顺序:先安装依赖关系,再进入到系统默认的安装包目录
src
,使用
wget
命令从网上下载
nginx1.22.1
版本的安装包,然后解压,再移动到
nginx
安
装目录,执行编译安装(预配置,编译,编译安装)
四、变量
1
、概念
变量用来存放系统或用户需要使用的特定参数或者值,变量的值可以根 据用户设定或者系统环境变化而相应变化,在Shell
脚本中使用变量,可 使脚本更加灵活,适应性更强。 与变量相对应的是常量,常量例如“Hello World”
,是不可改变的 变量可以给个变量名,假如为name
,值是可变的
2
、变量注意事项
变量命名规则:
必须由大写字母、小写字母、下划线、数字,并且首字 母不能是数字
在变量命名时:建议也简写出该变量是什么用处
变量值的类型:值的类型会分为整型、浮点型、字符串型、布尔型等, 而且使用变量需要指定类型Shell
默认的变量类型都是字符串,无需指 定类型
3
、变量的分类
(
1
)自定义变量
由用户自己定义、使用和修改
[root@localhost ~]
# A=1314 #
左边是变量名、右边是值
[root@localhost ~]
# echo $A
1314
[root@localhost ~]
# unset A #
清除变量
[root@localhost ~]
# echo $A
变量名
=
值中,等于号
=
之前和之后不能有空格,比如:
name = yang
,
这样是错的,
name=yang
才对
变量名
=
值中,值内如果输入数学算式,是没办法算出结果的,只会输
出字符串。
(
2
)环境变量
由系统维护,用于设置工作环境
$PWD
$SHELL
$USER
$PATH
[root@localhost ~]
# env #
查看所有环境变量
[root@localhost ~]
# echo $PWD
/root
[root@localhost ~]
# echo $SHELL
/bin/bash
[root@localhost ~]
# echo $USER
root
[root@localhost ~]
# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
其中
PATH
变量用于设置可执行程序的默认搜索路径,可以修改全局变 量文件/etc/profile
或修改某用户家目录下的
~/.bash_profile
文件永久改 变环境变量。
(
3
)位置变量
通过命令行给脚本程序传递参数
(
也属于预定义变量
) 为了在使用Shel
脚本程序时,方便通过命令行为程序提供操作参数, Bash引入了位置变量的概念位置变量有
,
n
,
n
为
1~9
之间的数字
$0
:第一个字段表示命令名或脚本名称
$1
:脚本要处理的第一个参数
$2
:脚本要处理的第二个参数
....
Shell
脚本最多可以直接处理
9
个参数
[root@localhost shell]
# vim ip.sh
#!/bin/bash
ifconfig
$1
|
grep
-w
inet |
awk
'{print $2}'
#
设置
⼀
个参数
:wq
[root@localhost shell]
# sh ./ip.sh ens32
192
.168.100.100
[root@localhost shell]
# vim ip.sh
#!/bin/bash
ifconfig
$1$2
|
grep
-w
inet |
awk
'{print $2}'
#
设置两个参 数
:wq
[root@localhost shell]
# sh ./ip.sh ens 32
192
.168.100.100
(
4
)预定义变量
Bash
中内置的一类变量,不能直接修改
预定义变量是
Bash
程序预先定义好的一类特殊变量,用户只能使用预定
义变量,而不能创建新的预定义变量,也不能直接为预定义变量赋值。
$*
:将所有参数作为整体
[root@localhost shell]
# vim ip.sh
#!/bin/bash
ifconfig
$1
|
grep
-w
inet |
awk
'{print $2}'
#
设置
⼀
个参数
:wq
[root@localhost shell]
# sh ./ip.sh ens32
192
.168.100.100
[root@localhost shell]
# vim ip.sh
#!/bin/bash
ifconfig
$1$2
|
grep
-w
inet |
awk
'{print $2}'
#
设置两个参
数
:wq
[root@localhost shell]
# sh ./ip.sh ens 32
192
.168.100.100
[root@localhost shell]
#
$@
:单个参数的组合,每个参数占一行
$0
:保存了脚本名称
$?
:保存命令或脚本的执行状态码
$#
:保存脚本要处理的参数的个数
[root@localhost shell]
# vim hehe.sh
#!/bin/bash
for
x
in
"
$*
"
#
将所有参数整合到一起,总共列为一行
do
echo
$x
done
for
y
in
"
$@
"
#
将所有参数单个列出,每个参数单列一行
do
echo
$y
done
:wq
[root@localhost shell]
# sh ./hehe.sh 1 2 3 4 5 6 # 查看$*
和
$@
的区别
1 2 3 4 5 6
# $*
的结果
1
2
3
4
5
6
# $@
的结果
[root@localhost shell]
# vim hehe.sh
#!/bin/bash
for
x
in
"
$*
"
do
echo
$x
done
for
y
in
"
$@
"
do
echo
$y
done
echo
"
该脚本是
:
$0
"
echo
"
此脚本
⼀
共处理了
$#
个参数
"
:wq
[root@localhost shell]
# sh hehe.sh 1 2 3 4 5 6
1 2 3 4 5 6
1
2
3
4
5
6
该脚本是
:hehe.sh
# $0
的结果,也就是该脚本的名称
此脚本
⼀
共处理了
6
个参数
# $#
的结果,执行脚本时,输入了多少参 数
4
、变量的定义与输出
(
1
)定义一个新的变量
格式:变量名
=
变量值
注意:变量名必须以字母或下划线开头,严格区分大小写
(
2
)变量符号运用
双引号:允许通过
$
符号引用其他变量值
单引号:禁止引用其他变量值,
$
视为普通字符
反撇号: 或
$():
命令替换,提取命令的执行结果
[root@localhost shell]
# X=aaa
[root@localhost shell]
# echo "$X" #
双引号可以使用变量
aaa
[root@localhost shell]
# echo '$X' #
单引号只显示符号内的 字符
$X
[root@localhost shell]
# ip1=`ifconfig ens32 | grep -w inet | awk '{print$2}'` # ``反撇号可以引用命令
[root@localhost shell]
# ip2=$(ifconfig ens32 | grep -w inet | awk '{print$2}') # $()与反撇号作用相同
[root@localhost shell]
# echo $ip1
192
.168.100.100
[root@localhost shell]
# echo $ip2
192
.168.100.100
[root@localhost shell]
# x=100
[root@localhost shell]
# y=50
[root@localhost shell]
# z=`expr $x + $y` #
整数运算
[root@localhost shell]
# echo $z
150
[root@localhost shell]
# x=1.4
[root@localhost shell]
# expr $x + 1 #
判断是否为浮点数
expr:
⾮
整数参数
[root@localhost shell]
# [ $? -ne 0 ] && echo "x
为浮点数
"
x
为浮点数
(
3
)输入和输出
输入格式:
read [-p "
显示的提示信息
"]
变量名
输出格式:
echo $
变量名
[root@localhost shell]
# read x y #
输
⼊
,变量输入,在下 一行输入
1 3
[root@localhost shell]
# echo $x $y #
输出,直接输出变量
1 3
[root@localhost shell]
# read -p "
请输
⼊
你要赋值的变量值
" x y
请输
⼊
你要赋值的变量值
1
5
[root@localhost shell]
# echo $x $y
1 5
[root@localhost shell]
# vim ip.sh #
编写一个查看
IP
的脚 本,内容如下
#!/bin/bash
read
-p
"
请输
⼊
接
⼝
名称:
"
x
#
输入
x
变量等于什么,脚本内不 用写,命令行输入该变量x
等于什么即可,该变量
x
可在脚本内引用
ifconfig
$x
|
grep
-w
inet |
awk
'{print $2}'
:wq
[root@localhost shell]
# sh ip.sh
请输
⼊
接
⼝
名称:
ens32
192
.168.100.100
[root@localhost shell]
# sh ip.sh
请输
⼊
接
⼝
名称:
lo
127
.0.0.1
[root@localhost shell]
# vim read.sh #
编写输入账号密码的脚 本,内容如下
#!/bin/bash
read
-p
"
请输
⼊
您的姓名:
"
name
#
该变量
name
是在命令行输入 的,相当于变量=
值
read
-p
"
请输
⼊
您的密码:
"
passwd
#
该变量
passwd
是在命令行输入 的,相当于变量=
值
if
[
$passwd
=
"123456"
];
then
# if
判断语句,如果
(if)
某某 等于某某,那么(then)
执行什么命令,否则
(else)
执行什么命令,结尾
fi
echo
"
你好,
$name
!"
else
echo
"
抱歉,您输
⼊
的密码不正确!
"
fi
:wq
[root@localhost shell]
# sh read.sh
请输
⼊
您的姓名:
admin
请输
⼊
您的密码:
112233
抱歉,您输
⼊
的密码不正确!
[root@localhost shell]
# sh read.sh
请输
⼊
您的姓名:
admin
请输
⼊
您的密码:
123456
你好,
admin !
5
、变量的作用范围
默认情况下,新定义的变量只在当前
Shell
环境中有效,因此称为局部变
量。当进入子程序或新的子
shell
时,局部变量将无法再使用。
为了使用户定义的变量在所有子
Shell
环境中能够继续使用,减少重复设
置工作,可以通过内部命令
export
将指定的变量导出为
“
全局变量
”
。
格式
1
:
export
变量名
格式
2
:
export
变量名
=
值
[root@localhost shell]
# x=aaa
[root@localhost shell]
# export y=bbb #
使
y=bbb
导出为 全局变量,即使下次更新环境变量,y
也会生效,相当于在
/etc/profile
内永 久赋值
[root@localhost shell]
# hostname shell
[root@localhost shell]
# bash
[root@shell shell]
# echo $x
[root@shell shell]
# echo $y
bbb
6
、变量的数学运算
(
1
)整数运算
格式:
expr
变量
1
运算符 变量
2
运算符 变量
3....
运算符:
+ - * /
(
+ - × ÷
)
[root@shell shell]
# x=123
[root@shell shell]
# y=111
[root@shell shell]
# expr $x + $y #
加
234
[root@shell shell]
# expr $x - $y #
减
12
[root@shell shell]
# expr $x \* $y #
乘
13653
[root@shell shell]
# expr $x / $y #
除
1
[root@shell shell]
# expr $x % $y #
余数计算
12
(
2
)精度计算
[root@shell shell]
# yum -y install bc #
精度计算前,先 安装bc
这个软件才可进行,否则只能进行整数运算
上次元数据过期检查:
2:45:58
前,执
⾏
于
2023
年
06
⽉
14
⽇
星期三
22
时 21分
58
秒。
软件包
bc-1.07.1-5.el8.x86_64
已安装。
依赖关系解决。
⽆
需任何处理。
完毕!
[root@shell shell]
# x=123
[root@shell shell]
# y=111
[root@shell shell]
# echo "scale=5; $x / $y" | bc
1
.10810
判断语法
一、条件判断
Shell
的返回值:运行一条命令,都会有一个返回值。
0
代表执行正常,非
0
代表命令执行异常。
[root@localhost test]
# ls /
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
[root@localhost test]
# echo $? # $?
保存了上条命令的返回值,
0
表示执行成功,非
0
表示执 行失败
0
[root@localhost test]
# ls /haha
ls
:
⽆
法访问
'/haha'
:
没有那个
⽂
件或
⽬
录
[root@localhost test]
# echo $?
2
二、
if
条件判断语句
1
、
if
单分支语句
if
条件判断
;
then
条件成
⽴
执
⾏
的命令
(
可以有多个命令,命令执行方式为逐行执行要么全执行,要么全不执行
)
fi
2
、
if
多分支语句
if
条件判断
;
then
条件成
⽴
执
⾏
的命令
(
可以有多个命令
)
else
条件不成
⽴
执
⾏
的命令
(
可以有多个命令
)
fi
条件判断:可以有数字判断、字符串判断、⽂件判断等
三、数字判断
1
、格式
-eq
:
equal
,等于,一般用于
[ $? -eq 0 ]
,也就是判断上条命令返回值等于
0
,直接数字
-eq
数
字也可以
equals
-ne
:
not equal
,不等于,一般用于
[ $? -ne 0 ]
,判断上条命令返回值不等于
0
-gt
:
greater than
,大于
-ge
:
greater or equal
,大于或等于
-lt
:
less than
,小于
-le
:
less or equal
,小于或等于
2
、应用示例
[root@localhost test]
# test 2 -eq 2 # test
:
shell
环境中,测试条件表达式的命令工具
[root@localhost test]
# echo $?
0
[root@localhost test]
# test 3 -eq 2 #
测试
3
等于
2
[root@localhost test]
# echo $?
1
#
返回值为
1
,说明测试的
3
等于
2
这条命令不成立
[root@localhost test]
# [ 2 -eq 2 ] #
编程中习惯使
⽤
[ ]
中括号
[root@localhost test]
# echo $?
0
[root@localhost test]
# [ 3 -eq 2 ]
[root@localhost test]
# echo $?
1
3
、创建简单的数字判断脚本
[root@localhost test]
# vim if.sh
#!/bin/bash
num1
=
3
#
给定变量
num1
num2
=
3
#
给定变量
num2
if
[
$num1
-eq
$num2
];then
#
判断
num1
变量是否等于
num2
echo
"
$num1
equal
$num2
"
#
如果等于,那么执行命令,
echo
输出
echo
"in if"
fi
:wq
[root@localhost test]
# sh ./if.sh
3
equal
3
in if
4
、创建检测网络是否畅通的脚本
[root@localhost test]
# vim ping.sh
#!/bin/bash
read
-p
"
请输
⼊
要测试的
⽹
址
:"
web
# read
:命令行内输入
web
的变量值
ping
-c
3
$web
&> /dev/null
# ping -c 3
,连接某个网站三次
if
[
$?
-eq
0
];then
#
如果
ping
命令执行成功,那么
echo
"
此时
⽹
络畅通!
"
#
输出
“
此时网络畅通
”
else
#
否则
echo
"
⽆
法访问,请检查
⽹
址是否输
⼊
正确或检查相关的
⽹
络配置!
"
#
输出
“
无法访 问...”
fi
# if
语句的结尾
:wq
[root@localhost test]
# sh ./ping.sh
请输
⼊
要测试的
⽹
址
:www.baidu.com
此时
⽹
络畅通!
四、字符串判断
1
、格式
[
字符串
1 ==
字符串
2 ]
字符串内容相同
[
字符串
1 !=
字符串
2 ]
字符串内容不同
[ -z
字符串
] 字符串内容为空
[ -n
字符串
] 字符串内容不为空
[root@localhost test]
# [ aaa == aaa ] # aaa
字符串等于
aaa
[root@localhost test]
# echo $?
0
#
命令返回值为
0
,说明
aaa==aaa
[root@localhost test]
# [ aaa == bbb ] # aaa
字符串等于
bbb
[root@localhost test]
# echo $?
1
#
命令返回值为非
0
,说明
aaa
不等于
bbb
[root@localhost test]
# [ -z aaa ] # aaa
字符串为空字符串
[root@localhost test]
# echo $?
1
#
命令返回值为非
0
,说明
aaa
字符串不为空
[root@localhost test]
# [ -z ] #
直接引用空字符串
[root@localhost test]
# echo $?
0
#
命令返回值为
0
,说明上条判断命令为空字符串
[root@localhost test]
# [ -n aaa ] # aaa
为非空字符串
[root@localhost test]
# echo $?
0
#
命令返回值为
0
,说明
aaa
为非空字符串
3
、案例
(
1
)创建简单的字符串判断脚本
[root@localhost test]
# vim zifu.sh
#!/bin/bash
read
-p
"
请输
⼊
账号
:"
name
if
[
"
$name
"
==
"admin"
];then
#
字符串判断需要加双引号
echo
"
欢迎您,
$name
!"
else
echo
"
系统未查询到此账号,请您重新输
⼊
!
"
fi
:wq
[root@localhost test]
# sh ./zifu.sh
请输
⼊
账号
:admin
欢迎您,
admin!
[root@localhost test]
# sh ./zifu.sh
请输
⼊
账号
:ads
系统未查询到此账号,请您重新输
⼊
!
(
2
)创建
rpm
查询软件是否安装的脚本
[root@localhost test]
# vim rpm.sh
#!/bin/bash
read
-p
"
请输
⼊
你要检测的
rpm
包
:"
rpmname
#
命令行输入
rpmname
变量值
result
=
`rpm -qa
$rpmname
`
#
设置
result
变量为
`rpm -qa $rpmname`
命令
if
[
-z
"
$result
"
];then
#
判断
result
变量内的命令执行后的值是否为空
echo
"
${rpmname}
is not find!"
#
如果为空则输出这条
else
echo
"
${rpmname}
is find!"
#
否则输出这条
fi
:wq
[root@localhost test]
# sh ./rpm.sh
请输
⼊
你要检测的
rpm
包
:nginx
nginx is not
find
!
[root@localhost test]
# sh ./rpm.sh
请输
⼊
你要检测的
rpm
包
:lrzsz
lrzsz is
find
!
五、文件、目录、权限的判断
示例
[root@localhost test]
# [ -e "/etc/passwd" ] #
判断
/etc/passwd
文件是否存在
[root@localhost test]
# echo $?
0
[root@localhost test]
# [ -e "/etc/haha" ] #
判断
/etc/haha
文件是否存在
[root@localhost test]
# echo $?
1
[root@localhost test]
# [ -f "/etc" ] #
判断
/etc
是否为普通文件
[root@localhost test]
# echo $?
1
[root@localhost test]
# [ -x "/bin/bash" ] #
判断
/bin/bash
是否可执行
[root@localhost test]
# echo $?
0
案例
[root@localhost test]
# vim install_nginx.sh
#!/bin/bash
if
[
-e
"/usr/local/nginx"
];then
# -e
:判断
nginx
软件目录是否存在
echo
"nginx is install!"
#
存在则输出一条
nginx
已安装的提示信息
exit
1
#
输出完已安装信息则退出脚本
else
#
若
nginx
软件目录不存在,则执行如下命令
yum
-y
install
gcc
gcc-c
++
make
pcre-devel openssl-devel
wget
cd
/usr/local/src/
wget
'http://nginx.org/download/nginx-1.22.1.tar.gz'
tar xf nginx-1.22.1.tar.gz
cd
nginx-1.22.1
./configure
--prefix
=
/usr/local/nginx
make
-j
4
&&make install
ln
-s
/usr/local/nginx/sbin/nginx /usr/bin/
/usr/local/nginx/sbin/nginx
fi
:wq
[root@localhost test]
# sh ./install_nginx.sh
六、与或判断
判断多个条件
多个条件其中一个成立,或
多个条件都要成立,与
或运算判断:
||
或,两个条件满足其一即可,还有
-o
与运算判断:
&&
与,两个条件都得满足才行,还有
-a
1
、或运算判断
[root@localhost test]
# vim huo.sh
#!/bin/bash
read
-p
"
请输
⼊
字符串
:"
name
if
[
"
$name
"
==
"haha"
]||[
"
$name
"
==
"hehe"
];then
#
这两个条件需满足其
一,也可使
⽤
[ "$name" =="haha" -o "$name" == "hehe" ]
echo
"
$name
is my want"
else
echo
"in else"
fi
:wq
[root@localhost test]
# sh ./huo.sh
请输
⼊
字符串
:haha
haha is my want
[root@localhost test]
# sh ./huo.sh
请输
⼊
字符串
:hehe
hehe is my want
[root@localhost test]
# sh ./huo.sh
请输
⼊
字符串
:lala
in else
2
、与运算判断
[root@localhost test]
# vim yu.sh
#!/bin/bash
read
-p
"
请输
⼊⼀
个数值
:"
age
if
[
$age
-gt
30
]&&[
$age
-lt
80
];then
#
这两个条件都得满足,大于
30
且小于
80
,可使用
[ $age -gt 30 -a $age -lt 80 ]
echo
"age>30 and age<80"
echo
"working"
else
echo
"in else"
fi
:wq
[root@localhost test]
# sh ./yu.sh
请输
⼊⼀
个数值
:60
age>30 and age<80
working
[root@localhost test]
# sh ./yu.sh
请输
⼊⼀
个数值
:90
in else
3
、混合判断
[root@localhost test]
# vim hun.sh
#!/bin/bash
read
-p
"
请输
⼊⼀
个数值
:"
age
if
[
$age
-gt
2
]&&[
$age
-lt
10
]||[
$age
-eq
100
];then
#
先做
||
前面的与判
断,再进行或判断,可使
⽤
[ $age -gt 2 -a $age -lt 10 -o $age -eq 100 ]
echo
"age is>2 and age is <10 or age ==100 "
else
echo
"in else"
fi
:wq
[root@localhost test]
# sh ./hun.sh
请输
⼊⼀
个数值
:7
age is>2 and age is <10 or age
==
100
[root@localhost test]
# sh ./hun.sh
请输
⼊⼀
个数值
:100
age is>2 and age is <10 or age
==
100
[root@localhost test]
# sh ./hun.sh
请输
⼊⼀
个数值
:30
in else
七、多重判断语法
elif
1
、
if
多分支语句结构
if
条件
1;
then
#
命令,条件
1
成
⽴
执
⾏
elif
条件
2;then
#
命令,条件
1
不成
⽴
,条件
2
成
⽴
执
⾏
elif
条件
3;then
#
命令,条件
1
不成
⽴
,条件
2
不成
⽴
,条件
3
成
⽴
执
⾏
else
#
命令 ,以上条件都不成
⽴
执
⾏
fi
2
、案例
[root@localhost test]
# vim fs.sh
#!/bin/bash
#
分数等级评定
read
-p
"
请输
⼊
您的分数(
0-100
)
:"
fs
if
[
$fs
-ge
0
-a
$fs
-lt
60
];then
echo
"
$fs
分,不及格!
"
elif
[
$fs
-ge
60
-a
$fs
-lt
70
];then
echo
"
$fs
分,及格!
"
elif
[
$fs
-ge
70
-a
$fs
-lt
85
];then
echo
"
$fs
分,良好!
"
elif
[
$fs
-ge
85
-a
$fs
-le
100
];then
echo
"
$fs
分,优秀!
"
else
echo
"
您输
⼊
的分数有误!
"
fi
:wq
[root@localhost test]
# sh ./fs.sh
请输
⼊
您的分数(
0-100
)
:20
20
分,不及格!
[root@localhost test]
# sh ./fs.sh
请输
⼊
您的分数(
0-100
)
:85
85
分,优秀!
[root@localhost test]
# sh ./fs.sh
请输
⼊
您的分数(
0-100
)
:70
70
分,良好!
[root@localhost test]
# sh ./fs.sh
请输
⼊
您的分数(
0-100
)
:123
您输
⼊
的分数有误!
八、多重判断的
case
语句
1
、
case
语句概述
case
语句是多分支选择语句
使用
case
语句改写
if
多分支可以使脚本结构更加清晰、层次分明。针对变量的不同取值,执行不同
的命令序列,
case
还支持正则。
2
、
case
语句的结构
case
$
变
量名称
in
模式
1)
命令序列
1
;;
模式
2)
命令序列
2
;;
*)
默
认命令序列
esac
3
、示例
提示用户输入一个字符,判断该字符是字母、数字或者其他字符的脚本
#!/bin/bash
#
击键类型识别
read
-p
"
请输
⼊⼀
个字符,并按
Enter
键确认
:"
key
case
$key
in
[a-z]|[A-Z])
# a
到
z
或
A
到
Z
,当变量输入为字母则执行下面的
echo
命令
echo
"
您输
⼊
的是
⼀
个 字
⺟
"
;;
[0-9])
# 0
到
9
,当变量输入为数字则执行下面的
echo
的命令
echo
"
您输
⼊
的是
⼀
个 数字
"
;;
*)
#
若变量输入为空格等其他符号字符,则执行下
面的
echo
命令
echo
"
您输
⼊
的是 空格、功能键或其他控制字符
"
;;
esac
:wq
[root@localhost test]
# sh ./hitkey.sh
请输
⼊⼀
个字符,并按
Enter
键确认
:5
您输
⼊
的是
⼀
个 数字
[root@localhost test]
# sh ./hitkey.sh
请输
⼊⼀
个字符,并按
Enter
键确认
:b
您输
⼊
的是
⼀
个 字
⺟
[root@localhost test]
# sh ./hitkey.sh
请输
⼊⼀
个字符,并按
Enter
键确认
:P
您输
⼊
的是
⼀
个 字
⺟
[root@localhost test]
# sh ./hitkey.sh
请输
⼊⼀
个字符,并按
Enter
键确认
:!
您输
⼊
的是 空格、功能键或其他控制字符
4
、案例
输入分数变量,然后判定等级
[root@localhost test]
# vim fscase.sh
#!/bin/bash
#
使
⽤
case
语句编写分数等级评定脚本
read
-p
"
请输
⼊
您的分数(
0-100
)
:"
fs
case
$fs
in
[0-9]|[0-5][0-9])
# 0
到
9
或
59
以内的两位数
echo
"
$fs
分,不及格!
"
;;
6
[0-9])
# 6
开头的两位数,若
$fs
输入为
0
,则判定为
60
,即执行下面的
echo
命令
echo
"
$fs
分,及格!
"
;;
7
[0-9]|8[0-5])
#
以
7
开头的两位数或以
8
开头的两位数
echo
"
$fs
分,良好!
"
;;
8
[6-9]|9[0-9]|100)
#
以
8
开头的两位数,第二位最少为
6
,也就是最小是
86 |
以
9
开头的两位数
| 100
echo
"
$fs
分,优秀!
"
;;
*)
#
输入不在上述规则内的其他字符,则
echo
如下命令
echo
"
您输
⼊
的分数有误!
"
esac
:wq
[root@localhost test]
# sh ./fscase.sh
请输
⼊
您的分数(
0-100
)
:5
5
分,不及格!
[root@localhost test]
# sh ./fscase.sh
请输
⼊
您的分数(
0-100
)
:58
58
分,不及格!
[root@localhost test]
# sh ./fscase.sh
请输
⼊
您的分数(
0-100
)
:69
69
分,及格!
[root@localhost test]
# sh ./fscase.sh
请输
⼊
您的分数(
0-100
)
:70
70
分,良好!
[root@localhost test]
# sh ./fscase.sh
请输
⼊
您的分数(
0-100
)
:89
89
分,优秀!
[root@localhost test]
# sh ./fscase.sh
请输
⼊
您的分数(
0-100
)
:100
100
分,优秀!
[root@localhost test]
# sh ./fscase.sh
请输
⼊
您的分数(
0-100
)
:110
您输
⼊
的分数有误!
shell脚本循环语法
一、
for
循环
1
、作用
读取不同的变量值,以逐个执行同一组命令
2
、结构
for
变量名
in
取值列表
(
范围
)
do
命令序列
done
取值列表:数字范围、字符串、多个字符串、提前设定好的变量等
for
默认以所有的空白字符进行分隔
: tab
、空格、回车,去循环处理
分隔成几段就循环几次
3
、示例
(
1
)分隔值循环
[root@localhost test]
# vim quzhi.sh
#!/bin/bash
for
home
in
北京 上海
⼴
州 深圳
# home
变量在北京、上海、广州、深圳这四个地名中间循环一
次
do
echo
"
$home
是个好地
⽅
!
"
done
:wq
[root@localhost test]
# bash quzhi.sh
北京 是个好地
⽅
!
上海 是个好地
⽅
!
⼴
州 是个好地
⽅
!
深圳 是个好地
⽅
!
(
2
)在命令结果中循环
[root@localhost test]
# vim 1.sh
#!/bin/bash
x
=
1
for
user
in
$(awk -F':' '{print
$1
}' /etc/passwd)
#
在
/etc/passwd
文件中以用
户名作为循环
do
echo
"
第
$x
⽤
户名称为
:
$user
"
let
x
=
x
+
1
done
echo
"
该系统有
$((
$x
-1))
个
⽤
户
"
:wq
[root@localhost test]
# bash 1.sh
第
1
⽤
户名称为
: root
...
省略部分内容
第
45
⽤
户名称为
: yunjisuan
第
46
⽤
户名称为
: apache
第
47
⽤
户名称为
: nginx
该系统有
47
个
⽤
户
(
3
)检测某个网段的存活主机
[root@localhost test]
# vim ping.sh
#!/bin/bash
for
IP
in
$(echo 192.168.33.{100..120})
# 192.168.33
网段的
100
到
120
的主机,在此
循环
do
ping
-c
2
-i
0
.1
$IP
&> /dev/null
if
[
$?
-eq
0
];then
echo
"Host
$IP
is up."
fi
done
:wq
[root@localhost test]
# bash ping.sh
Host
192
.168.100.100 is up.
Host
192
.168.100.101 is up.
(
4
)判断包是否已安装
[root@localhost test]
# vim 2.sh
#!/bin/bash
for
softpack
in
wget gcc
pcre pcre-devel zlib zlib-devel;do
soft_result
=
$(rpm -qa
$softpack
)
if
[
-z
"
$soft_result
"
];then
yum install
-y
$softpack
else
echo
"
$softpack
is installed"
fi
done
[root@localhost test]
# bash 2.sh
wget
is installed
gcc
is installed
pcre is installed
pcre-devel is installed
zlib is installed
zlib-devel is installed
二、
while
循环
1
、作用
重复测试某个条件,只要条件成立则反复执行
2
、结构
while
条件测试操作
do
命令序列
done
3
、
while
和
for
区别
while
循环也有条件判断,当条件成立的时候,会循环执行。当条件不成立退出
if
判断当条件成立时,会执行一次,然后退出。当条件不成立时直接退出
4
、示例
(
1
)批量添加用户
创建时交互输入用户前缀、创建用户个数、初始密码、过期时间
(
可选设置
)
,用户首次登陆强制要
求修改密码
[root@localhost test]
# vim useradd.sh #
批量创建
⽤
户脚本
#!/bin/bash
read
-p
"
请输
⼊
创建
⽤
户的名称前缀
:"
QZ
read
-p
"
请输
⼊
创建
⽤
户的个数
:"
NUM
read
-p
"
请输
⼊⽤
户的初始密码
:"
PS
i
=
1
while
[
$i
-le
$NUM
]
do
useradd
$QZ$i
echo
"
$PS
"
|passwd
--stdin
$QZ$i
&> /dev/null
chage
-d
0
$QZ$i
let i
++
done
:wq
[root@localhost test]
# bash useradd.sh
请输
⼊
创建
⽤
户的名称前缀
:admin
请输
⼊
创建
⽤
户的个数
:5
请输
⼊⽤
户的初始密码
:123456
[root@localhost test]
# tail /etc/passwd
[root@localhost test]
# vim userdel.sh #
批量删除
⽤
户脚本
#!/bin/bash
read
-p
"
请输
⼊
要删除
⽤
户的前缀
:"
QZ
read
-p
"
请输
⼊
要删除
⽤
户的个数
:"
NUM
i
=
1
while
[
$i
-le
$NUM
]
do
userdel
-r
$QZ$i
let i
++
done
:wq
[root@localhost test]
# bash userdel.sh
请输
⼊
要删除
⽤
户的前缀
:admin
请输
⼊
要删除
⽤
户的个数
:5
三、循环的
break
和
continue
break
直接结束循环,循环立即退出
continue
可以用来跳过一次循环,跳过后循环继续,直到循环停止
1
、示例
[root@localhost test]
# vim test.sh
#!/bin/bash
for
line
in
北京 上海
⼴
州 深圳
do
echo
$line
if
[
"
$line
"
==
"
上海
"
];then
$
循环到上海
⽴
即退出
break
fi
done
:wq
[root@localhost test]
# bash test.sh
北京
上海
[root@localhost test]
# vim test.sh
#!/bin/bash
for
line
in
北京 上海
⼴
州 深圳
do
if
[
"
$line
"
==
"
上海
"
];then
continue
fi
echo
$line
done
:wq
[root@localhost test]
# bash test.sh
北京
⼴
州
深圳
三、九九乘法表
[root@localhost test]
# vim 99.sh
#!/bin/bash
#
九九乘法表
for
i
in
{1..9};do
for
j
in
{1..9};do
echo
-n
"
$j
*
$i
=
$((
$i
*
$j
))
"
if
[
$j
==
$i
];then
echo
-e
'\n'
break
fi
done
done
:wq
[root@localhost test]
# bash 99.sh
1
*1
=
1
1
*2
=
2 2
*2
=
4
1
*3
=
3 2
*3
=
6 3
*3
=
9
1
*4
=
4 2
*4
=
8 3
*4
=
12 4
*4
=
16
1
*5
=
5 2
*5
=
10 3
*5
=
15 4
*5
=
20 5
*5
=
25
1
*6
=
6 2
*6
=
12 3
*6
=
18 4
*6
=
24 5
*6
=
30 6
*6
=
36
1
*7
=
7 2
*7
=
14 3
*7
=
21 4
*7
=
28 5
*7
=
35 6
*7
=
42 7
*7
=
49
1
*8
=
8 2
*8
=
16 3
*8
=
24 4
*8
=
32 5
*8
=
40 6
*8
=
48 7
*8
=
56 8
*8
=
64
1
*9
=
9 2
*9
=
18 3
*9
=
27 4
*9
=
36 5
*9
=
45 6
*9
=
54 7
*9
=
63 8
*9
=
72 9
*9
=
81
[root@localhost test]
#
[root@localhost test]
# vim 99-2.sh
#!/bin/bash
#
九九乘法表
i
=
1
while
[
$i
-le
9
];do
j
=
1
while
[
$j
-le
9
];do
echo
-n
"
$j
*
$i
=
$((
$i
*
$j
))
"
if
[
$j
-eq
$i
];then
echo
-e
'\n'
break
fi
let j
++
done
let i
++
done
:wq
[root@localhost test]
# bash 99-2.sh
1
*1
=
1
1
*2
=
2 2
*2
=
4
1
*3
=
3 2
*3
=
6 3
*3
=
9
1
*4
=
4 2
*4
=
8 3
*4
=
12 4
*4
=
16
1
*5
=
5 2
*5
=
10 3
*5
=
15 4
*5
=
20 5
*5
=
25
1
*6
=
6 2
*6
=
12 3
*6
=
18 4
*6
=
24 5
*6
=
30 6
*6
=
36
1
*7
=
7 2
*7
=
14 3
*7
=
21 4
*7
=
28 5
*7
=
35 6
*7
=
42 7
*7
=
49
1
*8
=
8 2
*8
=
16 3
*8
=
24 4
*8
=
32 5
*8
=
40 6
*8
=
48 7
*8
=
56 8
*8
=
64
1
*9
=
9 2
*9
=
18 3
*9
=
27 4
*9
=
36 5
*9
=
45 6
*9
=
54 7
*9
=
63 8
*9
=
72 9
*9
=
81
sed流式编辑器
一、概述
sed
是文本处理工具,读取文本内容,根据指定条件进行处理,可实现
增删改查的功能。
sed
依赖于正则表达式。
二、编辑命令格式
'/
地址
1
,地址
2/
操作
(
参数
)'
示例
(
1
)准备文件
[root@localhost test]
# vim test.txt
gd
god
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
IP
173
.16.16.1
pay
$1
80
:wq
(
2
)
p
打印
[root@localhost test]
# sed -n '12p' test.txt #
输出第
12
⾏
内容
HELLO
[root@localhost test]
# sed -n '3,5p' test.txt #
输出
3~5
⾏
内容
good
goood
gooood
[root@localhost test]
# sed -n 'p;n' test.txt #
输出奇数
⾏
gd
good
gooood
glad
abcdEfg
60115127Z
010
-66668888
IP
192
.168.1.108
pay
$1
80
[root@localhost test]
# sed -n 'n;p' test.txt #
输出偶数
⾏
god
goood
gold
gaad
food
HELLO
0666
-5666888
IP
173
.16.16.1
[root@localhost test]
# sed -n '1,6{p;n}' test.txt #
输出
1~6
⾏
之间的奇数
⾏
(第
1,3,5
⾏
)
gd
good
gooood
[root@localhost test]
# sed -n '/H/p' test.txt #
输出
包含字
⺟
H
的
⾏
HELLO
[root@localhost test]
# sed -n '/[A-Z]/p' test.txt #
输出所有
包含
⼤
写字
⺟
的
⾏
abcdEfg
60115127Z
HELLO
IP
192
.168.1.108
IP
173
.16.16.1
[root@localhost test]
# sed -n '$p' test.txt #
输出最后
⼀⾏
pay
$1
80
(
3
)
d
删除
[root@localhost test]
# sed '16d' test.txt #
删除第十六
行
gd
god
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
pay
$1
80
[root@localhost test]
# cat -n test.txt
1
gd
2
god
3
good
4
goood
5
gooood
6
7
gold
8
glad
9
10
gaad
11
abcdEfg
12
food
13
14
60115127Z
15
HELLO
16 010
-66668888
17 0666
-5666888
18
IP
192
.168.1.108
19
IP
173
.16.16.1
20
pay
$1
80
[root@localhost test]
# sed -i '/^$/d' test.txt #
删除
空行,
^$
:表示空行
[root@localhost test]
# cat -n test.txt
1
gd
2
god
3
good
4
goood
5
gooood
6
gold
7
glad
8
gaad
9
abcdEfg
10
food
11
60115127Z
12
HELLO
13 010
-66668888
14 0666
-5666888
15
IP
192
.168.1.108
16
IP
173
.16.16.1
17
pay
$1
80
[root@localhost test]
# sed -e '1d' -e '3d' test.txt #
删除第
1
⾏
和第
3
⾏
god
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
IP
173
.16.16.1
pay
$1
80
[root@localhost test]
# sed -e '1d;3d' test.txt
#
同样,删除第
1
⾏
和第
3
⾏
god
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
IP
173
.16.16.1
pay
$1
80
(
4
)
s
替换字符串
[root@localhost test]
# sed 's/o/O/g' test.txt #
将所
有
⼩
写
o
替换为
⼤
写
O
(
g
表示若同
⼀⾏
有多个
⼩
写
o
,全部替换,若不加
g
,则只
替换每
⾏
的第
⼀
个
⼩
写
o
)
gd
gOd
gOOd
gOOOd
gOOOOd
gOld
glad
gaad
abcdEfg
fOOd
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
IP
173
.16.16.1
pay
$1
80
[root@localhost test]
# sed '/^IP/ s/^/#/' test.txt #
以
IP
开头的
⾏
,
⾏⾸
加上
#
gd
god
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
#IP 192.168.1.108
#IP 173.16.16.1
pay
$1
80
[root@localhost test]
# sed 's/$/EOF/' test.txt #
在每
⾏⾏
尾插
⼊
字符串
EOF
gdEOF
godEOF
goodEOF
gooodEOF
goooodEOF
goldEOF
gladEOF
gaadEOF
abcdEfgEOF
foodEOF
60115127ZEOF
HELLOEOF
010
-66668888EOF
0666
-5666888EOF
IP
192
.168.1.108EOF
IP
173
.16.16.1EOF
pay
$1
80EOF
[root@localhost test]
# sed '20,25
s@/sbin/nologin@/bin/bash@' /etc/passwd
#
将
/etc/passwd
⽂
件
20~25
⾏
的
/sbin/nologin
替换为
/bin/bash
。如 果⽤
s///
的形式,将会多次使
⽤
转义符
\
,我们可以使
⽤
其他符号,如
@
进
⾏
分隔
(
5
)
c
替换整行
[root@localhost test]
# sed '2cAAAAAAA' test.txt #
将第
2
⾏
替换为
AAAAA
gd
AAAAAAA
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
IP
173
.16.16.1
pay
$1
80
[root@localhost test]
# sed '5,$ cAAAAA\nBBBBB' test.txt
#
把第
5
⾏⾄
最后
⼀⾏
的内容替换为两
⾏
,
AAAAA
和
BBBBB
(
\n
为换
⾏
)
gd
god
good
goood
AAAAA
BBBBB
(
6
)
r
追加指定文件到行后
[root@localhost test]
# sed '5r /etc/hostname' test.txt #
读
取
/etc/hostname
⽂
件内容在第
5
⾏
后
gd
god
good
goood
gooood
localhost.localdomain
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
IP
173
.16.16.1
pay
$1
80
(
7
)
a
追加指定内容到行后
[root@localhost test]
# sed '2aCCCCCCCCC' test.txt #
在第二行后追加
9
个
C
gd
god
CCCCCCCCC
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
IP
173
.16.16.1
pay
$1
80
[root@localhost test]
# sed '/[0-9]/a=====' test.txt #
在所有带数字的
⾏
下追
加
====
gd
god
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
=====
HELLO
010
-66668888
=====
0666
-5666888
=====
IP
192
.168.1.108
=====
IP
173
.16.16.1
=====
pay
$1
80
=====
(
8
)
i
追加指定内容到行前
[root@localhost test]
# sed '2iCCCCC' test.txt #
在第
二行之前追加
5
个
C
gd
CCCCC
god
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
IP
173
.16.16.1
pay
$1
80
(
9
)
w
另存为
[root@localhost test]
# sed '15,16w 123.txt' test.txt
#
将
15~16
⾏
内容另存到
123.txt
⽂
件中
gd
god
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
IP
173
.16.16.1
pay
$1
80
[root@localhost test]
# cat 123.txt
IP
192
.168.1.108
IP
173
.16.16.1
(
10
)
H
和
G
复制剪切粘贴
H
:复制到剪贴板
G
:将剪贴板中的内容追加到指定行后
[root@localhost test]
# sed '/IP/ {H;d};$G' test.txt
#
将包含字
⺟
IP
的
⾏
剪切到最后
⼀⾏
下
gd
god
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
pay
$1
80
IP
192
.168.1.108
IP
173
.16.16.1
[root@localhost test]
# sed '1,5H;15,16G' test.txt #
将
1~5
⾏
内容复制到
15
⾏
、
16
⾏
下
gd
god
good
goood
gooood
gold
glad
gaad
abcdEfg
food
60115127Z
HELLO
010
-66668888
0666
-5666888
IP
192
.168.1.108
gd
god
good
goood
gooood
IP
173
.16.16.1
gd
god
good
goood
gooood
pay
$1
80
三、
sed
命令引用变量
1. sed
命令使用单引号的情况下,可以使用
'"$var"'
引用(单引号,然后 双引号,变量):
sed
-i
'2s/node_base/'"
$i
"'/'
/etc/libvirt/qemu/
$i
.xml
1. sed
命令中使用双引号的情况下,直接
shell command
或者
$(shell command) 引用命令执行。
sed
-i
"2s/node_base/
$i
/"
/etc/libvirt/qemu/
$i
.xml