续Shell脚本学习 Day3

脚本开发

开发思路(使用nginx为例)

  1. 先思考脚本功能、作用
  2. 编写伪代码
  3. 定义变量,用于存储变化的值,便于后期维护
  4. 安装···
  5. 启动···
  6. 修改配置文件···
  7. 重启文件···

函数使用演示

编写demo1.sh脚本

1
2
3
4
5
6
7
#!/bin/bash

print_sth(){ #定义函数print_sth
echo "你好呀!"
}

print_sth #调用定义的函数

运行演示

1
2
3
[root@localhost ~]# vi demo1.sh
[root@localhost ~]# bash demo1.sh
你好呀!

实例一

接收用户输入的数字和符号实现加减乘除运算

编写demo2.sh脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/bin/bash
print_usage(){
printf "please enter on interger\n"
#给脚本的执行结果指定一个状态码、退出码
exit 1
}
#接受用户输入的命令,-p参数后面写用户可以看见的提示信息
read -p "please input your number:" firstnum

#对用户输入进行判断,注意语法格式
#显示用户输入纯数字
#中括号收尾需要有两个空格
#-n 参数是if的语句,对字符串判断。若字符串为空,条件就不成立,否则条件不成立
#利用sed将firstnum中所有的数字替换为空
if [ -n "`echo $firstnum|sed 's/[0-9]//g' `" ]
then
print_usage #用户未按要求输入纯数字时,报错,提示用户输入纯数字
exit 1
fi
#用户输入纯数字执行fi后的命令
#此时输入运算符
read -p "Please input your operator:" operator
#对运算符进行判断
#限制在+ - * /四个符号
if [ "${operator}" != "+" ] && [ "${operator}" != "-" ] && [ "${operator}" != "*" ] && [ "${operator}" != "/" ]
then
echo "只能输入+-*/四个符号"
exit 2
fi
#对第二个变量进行处理
read -p "please input your number:" secondnum
if [ -n "`echo $secondnum|sed 's/[0-9]//g'`" ]
then
print_usage
exit 3
fi
#最后进行数值计算,利用双小括号进行计算
echo "${firstnum}${operator}${secondnum}"'='"$((${firstnum}${operator}${secondnum}))"

运行演示

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# bash demo2.sh
please input your number:1
Please input your operator:*
please input your number:500
1*500=500
##########
[root@localhost ~]# bash demo2.sh
please input your number:1
Please input your operator+
please input your number:2
1+2=3

实例二

更简单的方法

使用参数传递,实现上面的功能

编写demo3.sh

1
2
#!/bin/bash
echo $(($1))

运行演示

1
2
[root@localhost ~]# bash demo3.sh 3*5
15

但这个脚本并没有我们demo2.sh的要严谨

实例三

开发检测nginx服务是否运行的脚本

首先引出while循环的使用

1
2
3
#while 无限循环的语法
#sleep 1 睡眠一秒再执行
while true;do echo "123456";sleep 1;done

执行后用Ctrl+C打断命令

编写demo4.sh脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/bash
CheckUrl(){
timeout=5 #超时
fails=0 #相当于定义一个计算器,连接失败次数
success=0 #连接成功次数
#循环的检测,循环执行一些命令
while true
do
#将${timeout}值传递给wget -timeout参数,--tries是wget的重连机制,后面接url是固有语法,-q -o是静默输出 将结果写入黑洞文件/dev/null中
wget --timeout=${timeout} --tries=1 http://lptexas-cub.github.io/ -q -o /dev/null
#echo $?输出状态码
#-ne 表示不等于 !=
#注意中括号中间首尾空格语法
if [ $? -ne 0 ] #状态码不等于0
then
let fails=fails+1 #说明连接失败,fails加1
else #否则,即状态码等于0的时候
let success+=1 #连接成功
fi #闭环,中端if语句
#判断成功次数大于等于1时,就可以得出该网站是正确访问的
#-ge 表示大于等于 >=
if [ ${success} -ge 1 ]
then
echo "网站运行正常!"
exit 0 #返回状态码,0表示正常
fi
#当错误次数大于2时,就告警
if [ ${fails} -ge 2 ];then
echo "网站访问异常!"
exit 2
fi
done
}
#记得定义后,调用才会运行!
CheckUrl

http://……./ 处可以使用自己的网站作为测试

let命令运算操作

let命令的执行效果等同于双小括号

但是,双小括号效率更高

let命令实践

1
2
3
4
[root@localhost ~]# num=8
[root@localhost ~]# num=num+8
[root@localhost ~]# echo $num
num+8

可见bash原生命令并不支持运算!

这时我们使用let命令操作

1
2
3
4
[root@localhost ~]# num=8
[root@localhost ~]# let num=num+8
[root@localhost ~]# echo $num
16

对比一下使用双小括号操作

1
2
3
4
[root@localhost ~]# num=8
[root@localhost ~]# num=$((num+8))
[root@localhost ~]# echo $num
16

expr命令运算操作

expr命令基于空格,对于一些运算符需要加 \ 转义后才能使用,如:* 使用expr时需要用 *

expr帮助

1
expr --help
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
用法:expr 表达式
 或:expr 选项

--help 显示此帮助信息并退出
--version 显示版本信息并退出

将表达式的值列印到标准输出,分隔符下面的空行可提升算式优先级。
可用的表达式有:

ARG1 | ARG2 若ARG1 的值不为0 或者为空,则返回ARG1,否则返回ARG2

ARG1 & ARG2 若两边的值都不为0 或为空,则返回ARG1,否则返回 0

ARG1 < ARG2 ARG1 小于ARG2
ARG1 <= ARG2 ARG1 小于或等于ARG2
ARG1 = ARG2 ARG1 等于ARG2
ARG1 != ARG2 ARG1 不等于ARG2
ARG1 >= ARG2 ARG1 大于或等于ARG2
ARG1 > ARG2 ARG1 大于ARG2

ARG1 + ARG2 计算 ARG1 与ARG2 相加之和
ARG1 - ARG2 计算 ARG1 与ARG2 相减之差

ARG1 * ARG2 计算 ARG1 与ARG2 相乘之积
ARG1 / ARG2 计算 ARG1 与ARG2 相除之商
ARG1 % ARG2 计算 ARG1 与ARG2 相除之余数

字符串 : 表达式 定位字符串中匹配表达式的模式

match 字符串 表达式 等于"字符串 :表达式"
substr 字符串 偏移量 长度 替换字符串的子串,偏移的数值从 1 起计
index 字符串 字符 在字符串中发现字符的地方建立下标,或者标0
length 字符串 字符串的长度
+ TOKEN interpret TOKEN as a string, even if it is a
keyword like 'match' or an operator like '/'

( EXPRESSION ) value of EXPRESSION

请注意有许多运算操作符都可能需要由 shell 先实施转义。
如果参与运算的 ARG 自变量都是数字,比较符就会被视作数学符号,否则就是多义的。
模式匹配会返回"\"和"\"之间被匹配的子字符串或空(null);如果未使用"\"和"\",
则会返回匹配字符数量或是 0。

若表达式的值既不是空也不是 0,退出状态值为 0;若表达式的值为空或为 0,
退出状态值为 1。如果表达式的句法无效,则会在出错时返回退出状态值 3。

GNU coreutils online help: <http://www.gnu.org/software/coreutils/>
请向<http://translationproject.org/team/zh_CN.html> 报告expr 的翻译错误
要获取完整文档,请运行:info coreutils 'expr invocation'

我们还可以通过手册对expr命令进行了解

1
man expr

expr命令实践

见Shell脚本学习Day3

expr模式匹配

expr命令支持模式匹配功能(正则表达式)

2个特殊符号

  • : 计算字符串数量,如abc 3个字符
  • .* 任意字符串重复0次或者多次

语法

expr <字符串> “:” “.*”

实例

1
2
3
4
[root@localhost ~]# expr abc123 ":" ".*"
6
[root@localhost ~]# expr abc.png ":" ".*\.png" #使用了反斜杠转义,匹配以.png结尾的字符并计算字符串数目
3

bc命令运算操作

bc命令当做计算器来使用,是命令行的计算器

两种形式:交互式与非交互式

支持小数!但除法不支持

bc命令结合管道符

1
echo "4*4"|bc

bc案例

计算1~100的总和

数学公式:1+2+3+…+100

法一

使用{1..100}生成1到100的序列,再使用tr将结果中的空格替换为+,最后交给bc命令计算结果

1
echo {1..100}|tr " " "+"|bc

运行演示

1
2
3
4
5
6
[root@localhost ~]# echo {1..100}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
[root@localhost ~]# echo {1..100}|tr " " "+"
1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100
[root@localhost ~]# echo {1..100}|tr " " "+"|bc
5050

法二

使用seq生成序列

seq的默认分隔符为换行符,可以使用-s参数指定分隔符

1
seq -s "+" 100 |bc

运行演示

1
2
[root@localhost ~]# seq -s "+" 100 |bc
5050

awk命令支持数值运算操作

语法:

echo “参数1 参数2 … …” |awk ‘{print $1<运算符>$2<运算符>$3… …}’

awk支持小数计算

awk实例

1
2
[root@localhost ~]# echo "0.1 2.1 3"|awk '{print $1+$2*$3}'
6.4

中括号运算操作

语法:

$[表达式]

中括号实例

1
2
[root@localhost ~]# echo $[1+2]
3

知识点补充

read命令

shell变量除了直接赋值,或者脚本传递参数,还有就是read命令读取。

read命令是内置命令

1
2
[root@localhost ~]#  type read
read 是 shell 内嵌

相关参数

-t 等待用户输入的时间,超时命令终止

-p 设置提示信息

1
2
3
4
5
6
7
[root@localhost ~]# read -t 2 -p "请输入:" vars
请输入:[root@localhost ~]#
#####
[root@localhost ~]# read -t 2 -p "请输入:" vars
请输入:123
[root@localhost ~]# echo $vars
123

touch命令

语法

touch [-acfm][-d<日期时间>][-r<参考文件或目录>] [-t<日期时间>][–help][–version][文件或目录…]

Linux 用户和用户组管理

添加用户

使用useradd命令

语法:

useradd 选项 用户名

参数说明:

  • 选项:

    • -c comment 指定一段注释性描述。
    • -d 目录 指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主目录。
    • -g 用户组 指定用户所属的用户组。
    • -G 用户组,用户组 指定用户所属的附加组。
    • -s Shell文件 指定用户的登录Shell。
    • -u 用户号 指定用户的用户号,如果同时有-o选项,则可以重复使用其他用户的标识号。
  • 用户名:

    指定新账号的登录名。

实例1

1
useradd –d /home/sam -m sam

此命令创建了一个用户sam,其中-d和-m选项用来为登录名sam产生一个主目录 /home/sam(/home为默认的用户主目录所在的父目录)。

切换用户

1
su [-fmp] [-c command] [-s shell] [--help] [--version] [-] [USER [ARG]]

shell条件测试

所谓条件测试,就是得出真假的概念

shell提供条件测试的语法

  1. test命令
  2. 中括号
  3. [[ ]] 双中括号
  4. (( )) 双小括号

条件测试常用语法

test条件命令测试

评估一个表达式,结果是真或假

如果结果为真,状态码结果为0;否则,状态码非0

$?取得状态码值

相关参数

-e 判断文件或目录是否存在,存在返回真,否则返回假

语法

1
test 测试参数 测试对象 对结果进行判断执行的逻辑动作

test命令实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost ~]# test -e test_file
[root@localhost ~]# echo $?
1
#######
[root@localhost ~]# ls
anaconda-ks.cfg demo1.sh demo3.sh hello.sh sub_str
blog demo2.sh demo4.sh node-v16.16.0-linux-x64
[root@localhost ~]# test -e hello.sh
[root@localhost ~]# echo $?
0
###
[root@localhost ~]# test -e hello.sh && echo "文件存在!"
文件存在!
[root@localhost ~]# echo $?
0

test语法大全

参阅:知无涯学无尽 略有修改

常用

1
2
3
4
5
6
7
8
#文件状态
-e 文件或目录是否存在
-f 文件是否存在
-d 目录是否存在
#权限
–r 文件存在并且可读
–w 文件存在并且可写
–x 文件存在并且可执行

判断表达式

1
2
3
4
if test  (表达式为真)
if test !表达式为假
test 表达式1 –a 表达式 2 两个表达式都为真
test 表达式1 –o 表达式2 两个表达式有一个为真

判断字符串

1
2
3
4
test –n 字符串         字符串的长度非零,有内容为真
test –z 字符串 字符串的长度为零,无内容为真
test 字符串1 = 字符串2 字符串相等
test 字符串1 != 字符串2 字符串不等

判断整数

1
2
3
4
5
6
test 整数1 –eq 整数2    整数相等(equal)
test 整数 1 –ge 整数2 整数1大于等于整数2(greater equal)
test 整数1 –gt 整数 2 整数1大于整数2(greater than)
test 整数1 –le 整数 2 整数1小于等于整数2(less equal)
test 整数1 –lt 整数 2 整数1小于整数2(less than)
test 整数1 –ne 整数 2 整数1不等于整数2 (not equal)

判断文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#两个文件之间的比较
test File1 –ef File2 两个文件具有同样的设备号和i结点号
test File1 –nt File2 文件1比文件2 新
test File1 –ot File2 文件1比文件2 旧
#
test –b File 文件存在并且是块设备文件
test –c File 文件存在并且是字符设备文件
test –d File 文件存在并且是目录
test –e File 文件存在
test –f File 文件存在并且是正规文件
test –g File 文件存在并且是设置了组ID
test –G File 文件存在并且属于有效组ID
test –h File 文件存在并且是一个符号链接(同-L)
test –k File 文件存在并且设置了sticky位
test –b File 文件存在并且是块设备文件
test –L File 文件存在并且是一个符号链接(同-h)
test –o File 文件存在并且属于有效用户ID
test –p File 文件存在并且是一个命名管道
test –s File 文件存在并且是一个套接字
test –t FD 文件描述符是在一个终端打开的
test –u File 文件存在并且设置了它的set-user-id位
#文件权限类
test –r File 文件存在并且可读
test –w File 文件存在并且可写
test –x File 文件存在并且可执行

test xxx 可以简写成 [ xxx ] 的形式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
注意:在使用"["简写test时,左中括号后面的空格和右括号前面的空格是必需的,如果没有空格,Shell不可能辨别表达式何时开始何时结束.

也就是说

test option file

可以全部改写成:

[ option file ]

例如:

test –w File

改写成

[ –w File ]

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 判断第一个参数是否为空字符串,不空则打印
if test -n "$1"
then
echo "$1"
fi

测试,放到文件当中
#!/bin/sh
if test -n "$1"
then
echo "$1"
fi

执行
chmod +x test.sh
./test.sh www.linuxpig.com

test命令实践

补充:shell对于真假判断的逻辑,提供&&与运算、||或运算,并且是递进关系

说明

1
2
A条件 && B条件  当A条件成立,并且执行B条件
A条件 || B条件 当A条件不成立,才会执行B条件

实例

1
2
3
4
5
6
7
[root@localhost ~]# ls
anaconda-ks.cfg demo1.sh demo3.sh hello.sh sub_str
blog demo2.sh demo4.sh node-v16.16.0-linux-x64
[root@localhost ~]# test -e hello.sh && echo "文件存在!"||echo "文件不存在!!"
文件存在!
[root@localhost ~]# test -e hello1.sh && echo "文件存在!"||echo "文件不存在!!"
文件不存在!!

中括号语法条件测试

脚本中经常进行条件测试,用到最多的,都是中括号[ ]

test和[]的作用相同

注意:[ ] 前后都要加空格!

1
2
[root@localhost ~]# [ -e hello.sh ] && echo "文件存在"
文件存在

补充:

在条件测试中使用变量,必须添加双引号!!

实例

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost ~]# file=test
[root@localhost ~]# touch test
[root@localhost ~]# [ -e "$file" ] && echo "文件存在" || echo "文件不存在"
文件存在
[root@localhost ~]# rm test
rm:是否删除普通空文件 "test"?y
[root@localhost ~]# [ -e "$file" ] && echo "文件存在" || echo "文件不存在"
文件不存在
########
[root@localhost ~]# touch file
[root@localhost ~]# [ -e $file ] && echo "文件存在" || echo "文件不存在"
文件不存在

双中括号条件测试

与单中括号、test效果相同

特点:双中括号还支持正则表达式

注意:

和单括号一样需要加括号

双小括号条件测试