目录
第一章 Shell基础知识 .............................................................. 8
1.1 Shell简介 ...................................................................... 8
1.2 Shell基本分两大类 .............................................................. 9
1.3 第一个Shell脚本 ................................................................ 9
1.4 Shell变量 ...................................................................... 9
1.5 变量引用 ....................................................................... 12
1.6 双引号和单引号 ................................................................. 13
1.7 注释 ........................................................................... 14
第二章 Shell字符串处理之${} ....................................................... 14
2.1 获取字符串长度 ................................................................. 14
2.2 字符串切片 ..................................................................... 14
2.3 替换字符串 ..................................................................... 15
2.4 字符串截取 ..................................................................... 15
2.5 变量状态赋值 ................................................................... 16
2.6 字符串颜色 ..................................................................... 16
第三章 Shell表达式与运算符 ........................................................ 17
3.1 条件表达式 ..................................................................... 17
3.2 整数比较符 ..................................................................... 18
3.3 字符串比较符 ................................................................... 18
3.4 文件测试 ....................................................................... 19
3.5 布尔运算符 ..................................................................... 19
3.6 逻辑判断符 ..................................................................... 20
3.7 整数运算 ....................................................................... 20
3.8 其他运算工具(let/expr/bc) .................................................... 21
3.9 Shell括号用途总结 ............................................................. 22
第四章 Shell流程控制 ............................................................. 23
4.1 if语句 ........................................................................ 23
4.2 for语句 ....................................................................... 25
4.3 while语句 ..................................................................... 26
4.4 break和continue语句 .......................................................... 28
4.5 case语句 ...................................................................... 29
4.6 select语句 .................................................................... 30
第五章 Shell函数与数组 ........................................................... 32
5.1 函数 ........................................................................... 32
5.2 数组 ........................................................................... 34
第六章 Shell正则表达式 ........................................................... 35
第七章 Shell文本处理三剑客 ........................................................ 38
7.1 grep ........................................................................... 38
7.2 sed ............................................................................ 42
7.2.1 匹配打印(p) .............................................................. 44
7.2.2 匹配删除(d) .............................................................. 46
7.2.3 替换(s///) ............................................................... 47
7.2.4 多重编辑(-e) ............................................................. 50
7.2.5 添加新内容(a、i和c) ..................................................... 50
7.2.6 读取文件并追加到匹配行后(r) .............................................. 52
7.2.7 将匹配行写到文件(w) ...................................................... 52
7.2.8 读取下一行(n和N) ........................................................ 53
7.2.9 打印和删除模式空间第一行(P和D) .......................................... 55
7.2.10 保持空间操作(h与H、g与G和x) .......................................... 55
7.2.11 标签(:、b和t) .......................................................... 57
7.2.12 忽略大小写匹配(I) ....................................................... 59
7.2.13 获取总行数(#) ........................................................... 59
8.3 awk ............................................................................ 59
8.3.1 选项 ....................................................................... 60
8.3.2 模式 ....................................................................... 60
8.3.3 内置变量 ................................................................... 65
8.3.4 操作符 ..................................................................... 70
8.3.5 流程控制 ................................................................... 74
8.3.6 数组 ....................................................................... 77
8.3.7 内置函数 ................................................................... 80
8.3.8 I/O语句 ................................................................... 84
8.3.9 printf语句 ................................................................ 87
8.3.10 自定义函数 ................................................................ 88
8.3.11 需求案例 .................................................................. 89
第八章 Shell标准输入、输出和错误 .................................................. 94
8.1 标准输入、输出和错误 ........................................................... 94
8.2 重定向符号 ..................................................................... 94
8.3 重定向输出 ..................................................................... 95
8.4 重定向输入 ..................................................................... 95
8.5 重定向标准输出和标准错误 ....................................................... 95
8.6 重定向到空设备 ................................................................. 96
8.7 read命令 ...................................................................... 97
第九章 Shell信号发送与捕捉 ........................................................ 98
9.1 Linux信号类型 ................................................................. 98
9.2 kill命令 ..................................................................... 100
9.3 trap命令 ..................................................................... 100
第十章 Shell编程时常用的系统文件 ................................................. 102
10.1 Linux系统目录结构 ........................................................... 102
10.2 环境变量文件 ................................................................. 103
10.3 系统配置文件 ................................................................. 103
10.4 /dev目录 .................................................................... 104
10.5 /proc目录 ................................................................... 104
10.5.1 /proc .................................................................... 105
10.5.2 /proc/net ................................................................ 105
10.5.3 /proc/sys ................................................................ 106
第十一章 Shell常用命令与工具 ..................................................... 108
11.1 ls ........................................................................... 108
11.2 echo ......................................................................... 109
11.3 printf ....................................................................... 109
11.4 cat .......................................................................... 110
11.5 tac .......................................................................... 111
11.6 rev .......................................................................... 111
11.7 wc ........................................................................... 111
11.8 cp ........................................................................... 111
11.9 mkdir ........................................................................ 112
11.10 mv .......................................................................... 112
11.11 rename ...................................................................... 112
11.12 dirname ..................................................................... 113
11.13 basename .................................................................... 113
11.14 du .......................................................................... 113
11.15 cut ......................................................................... 114
11.16 tr .......................................................................... 114
11.17 stat ........................................................................ 115
11.18 seq ......................................................................... 115
11.19 shuf ........................................................................ 116
11.20 sort ........................................................................ 116
11.21 uniq ........................................................................ 117
11.22 tee ......................................................................... 118
11.23 join ........................................................................ 119
11.24 paste ....................................................................... 119
11.25 head ........................................................................ 120
11.26 tail ........................................................................ 120
11.27 find ........................................................................ 120
11.28 xargs ....................................................................... 122
11.29 nl .......................................................................... 122
11.30 date ........................................................................ 123
11.31 wget ........................................................................ 124
11.32 curl ........................................................................ 126
11.33 scp ......................................................................... 127
11.34 rsync ....................................................................... 128
11.35 nohup ....................................................................... 128
11.36 iconv ....................................................................... 129
11.37 uname ....................................................................... 129
11.38 sshpass ..................................................................... 129
11.39 tar ......................................................................... 130
11.40 logger ...................................................................... 130
11.41 netstat ..................................................................... 131
11.42 ss .......................................................................... 131
11.43 lsof ........................................................................ 132
11.44 ps .......................................................................... 133
11.45 top ......................................................................... 134
11.46 free ........................................................................ 135
11.47 df .......................................................................... 136
11.48 vmstat ...................................................................... 136
11.49 iostat ...................................................................... 137
11.50 sar ......................................................................... 137
11.51 dstat ....................................................................... 138
11.52 ip .......................................................................... 138
11.53 nc .......................................................................... 139
11.54 time ........................................................................ 140
11.55 eval ........................................................................ 141
11.56 ssh ......................................................................... 141
11.57 iptables .................................................................... 142
第十二章 Shell脚本编写实战 ....................................................... 145
12.1 获取随机字符串或数字 ......................................................... 145
12.2 定义一个颜色输出字符串函数 ................................................... 146
12.3 批量创建用户 ................................................................. 147
12.4 检查软件包是否安装 ........................................................... 147
12.5 检查服务状态 ................................................................. 147
12.6 检查主机存活状态 ............................................................. 148
12.7 监控CPU、内存和硬盘利用率 ................................................... 149
12.8 批量主机磁盘利用率监控 ....................................................... 150
12.9 检查网站可用性 ............................................................... 151
12.10 检查MySQL主从同步状态 ...................................................... 152
12.11 屏蔽访问频繁的IP ........................................................... 153
12.12 判断输入是否为IP ........................................................... 154
12.13 判断输入是否为数字 .......................................................... 155
12.14 找出包含关键字的文件 ........................................................ 155
12.15 监控目录,将新创建的文件名追加到日志中 ...................................... 156
12.16 多个网卡选择 ................................................................ 156
12.17 查看网卡实时流量 ............................................................ 157
12.18 MySQL数据库备份 ............................................................ 158
12.19 Nginx启动脚本 .............................................................. 158
12.20 选择SSH连接主机 ............................................................ 160
12.21 FTP下载文件 ................................................................ 160
12.22 输入五个100数之内的字符,统计和、最小和最大 ................................ 161
12.23 将结果分别赋值给变量 ........................................................ 161
12.24 批量修改文件 ................................................................ 162
12.25 统计当前目录中以.html结尾的文件总大小 ...................................... 162
12.26 扫描主机端口状态 ............................................................ 162
12.27 Expect实现SSH免交互执行命令 ............................................... 163
12.28 批量修改服务器用户密码 ...................................................... 165
12.29 打印乘法口诀 ................................................................ 165
12.30 getopts工具完善脚本命令行参数 .............................................. 166
第一章 Shell基础知识
1.1 Shell简介
Shell是一个C语言编写的脚本语言,它是用户与Linux的桥梁,用户输入命令交给Shell处理,
Shell将相应的操作传递给内核(Kernel),内核把处理的结果输出给用户。
下面是流程示意图:
Shell既然是工作在Linux内核之上,那我们也有必要了解下Linux相关知识。
Linux是一套免费试用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。
1983年9月27日,Richard Stallman(理查德-马修-斯托曼)发起GNU计划,它的目标是创建一套完全自由的操作系统。为保证GNU软件可以自由的使用、复制、修改和发布,所有的GNU软件都有一份在禁止其他人添加任何限制的情况下授权所有权利给任何人的协议条款,GNU通用公共许可证(GNU General Plubic License,GPL),说白了就是不能做商业用途。
GNU是"GNU is Not Unix"的递归缩写。UNIX是一种广泛使用的商业操作系统的名称。
1985年,Richard Stallman又创立了自由软件基金会(Free Software Foundation,FSF)来为
GNU计划提供技术、法律以及财政支持。
1990年,GNU计划开发主要项目有Emacs(文本编辑器)、GCC(GNU Compiler Collection,GNU编译器集合)、Bash等,GCC是一套GNU开发的编程语言编译器。还有开发一些UNIX系统的程序库和工具。
1991年,Linuxs Torvalds(林纳斯- 托瓦兹)开发出了与UNIX兼容的Linux操作系统内核并在
GPL条款下发布。
1992年,Linux与其他GUN软件结合,完全自由的GUN/Linux操作系统正式诞生,简称Linux。
1995年1月,Bob Young创办ACC公司,以GNU/Linux为核心,开发出了RedHat Linux商业版。
Linux基本思想有两点:第一,一切都是文件;第二,每个软件都有确定的用途。与Unix思想十分相近。
1.2 Shell基本分两大类
1.2.1 图形界面Shell(GUI Shell)
GUI为Unix或者类Unix操作系统构造一个功能完善、操作简单以及界面友好的桌面环境。主流桌面环境有KDE,Gnome等。
1.2.2 命令行界面Shell(CLI Shell)
CLI是在用户提示符下键入可执行指令的界面,用户通过键盘输入指令,完成一系列操作。在Linux系统上主流的CLI实现是Bash,是许多Linux发行版默认的Shell。还有许多Unix上 Shell,例如tcsh、csh、ash、bsh、ksh等。
1.3 第一个Shell脚本
本教程主要讲解在大多Linux发行版下默认Bash Shell。Linux系统是RedHat下的CentOS操作系统,完全免费。与其商业版RHEL(Red Hat Enterprise Linux)出自同样的源代码,不同的是 CentOS并不包含封闭源代码软件和售后支持。
用vi打开test.sh,编写:
# vi test.sh #!/bin/bash echo "Hello world!"
第一行指定解释器,第二行打印Hello world!写好后,开始执行,执行Shell脚本有三种方法:方法1:直接用bash解释器执行
# bash test.sh Hello world!
当前终端会新生成一个子bash去执行脚本。方法2:添加可执行权限
# ll test.sh
-rw-r--r--. 1 root root 32 Aug 18 01:07 test.sh
# chmod +x test.sh
# ./test.sh
-bash: ./test.sh: Permission denied
# chmod +x test.sh # ./test.sh # ./在当前目录 Hello world!
这种方式默认根据脚本第一行指定的解释器处理,如果没写以当前默认Shell解释器执行。方法3:source命令执行,以当前默认Shell解释器执行
# source test.sh Hello world!
1.4 Shell变量
1.4.1 系统变量在命令行提示符直接执行env、set查看系统或环境变量。env显示用户环境变量,set显示Shell 预先定义好的变量以及用户变量。可以通过export导出成用户变量。
一些写Shell脚本时常用的系统变量:
$SHELL 默认Shell
$HOME 当前用户家目录
$IFS 内部字段分隔符
$LANG 默认语言
$PATH 默认可执行程序路径
$PWD 当前目录
$UID 当前用户ID
$USER 当前用户
$HISTSIZE 历史命令大小,可通过HISTTIMEFORMAT变量设置命令执行时间
$RANDOM 随机生成一个0至32767的整数
$HOSTNAME 主机名
1.4.2 普通变量与临时环境变量
普通变量定义:VAR=value
临时环境变量定义:export VAR=value 变量引用:$VAR
下面看下他们之间区别:
Shell进程的环境变量作用域是Shell进程,当export导入到系统变量时,则作用域是Shell进程及其Shell子进程。
ps axjf输出的第一列是PPID(父进程ID),第二列是PID(子进程ID)
当SSH连接Shell时,当前终端PPID(-bash)是sshd守护程序的PID(root@pts/0),因此在当前终端下的所有进程的PPID都是-bash的PID,比如执行命令、运行脚本。
所以当在-bash下设置的变量,只在-bash进程下有效,而-bash下的子进程bash是无效的,当 export后才有效。
进一步说明:再重新连接SSH,去除上面定义的变量测试下
所以在当前shell定义的变量一定要export,否则在写脚本时,会引用不到。还需要注意的是退出终端后,所有用户定义的变量都会清除。
在/etc/profile下定义的变量就是这个原理,后面有章节会讲解Linux常用变量文件。
1.4.3 位置变量
位置变量指的是函数或脚本后跟的第n个参数。
$1-$n,需要注意的是从第10个开始要用花括号调用,例如${10} shift可对位置变量控制,例如:
#!/bin/bash echo "1: $1" shift echo "2: $2" shift echo "3: $3"
# bash test.sh a b c
1: a
2: c
3:
每执行一次shift命令,位置变量个数就会减一,而变量值则提前一位。shift n,可设置向前移动 n位。
1.4.4 特殊变量
$0 脚本自身名字
$? 返回上一条命令是否执行成功,0为执行成功,非0则为执行失败
$# 位置参数总数
$* 所有的位置参数被看做一个字符串
$@ 每个位置参数被看做独立的字符串
$$ 当前进程PID
$! 上一条运行后台进程的PID
1.5 变量引用
赋值运算符 示例
= 变量赋值
+= 两个变量相加
1.5.1 自定义变量与引用
# VAR=123
# echo $VAR
123
# VAR+=456
# echo $VAR 123456
Shell中所有变量引用使用$符,后跟变量名。有时个别特殊字符会影响正常引用,那么需要使用${VAR},例如:
# VAR=123
# echo $VAR
123
# echo $VAR_ # Shell允许VAR_为变量名,所以此引用认为这是一个有效的变量名,故此返回空
# echo ${VAR}
123
还有时候变量名与其他字符串紧碍着,也会误认为是整个变量:
# echo $VAR456
# echo ${VAR}456 123456
1.5.2 将命令结果作为变量值
# VAR=`echo 123`
# echo $VAR
123
# VAR=$(echo 123)
# echo $VAR
123
这里的反撇号等效于$(),都是用于执行Shell命令。
1.6 双引号和单引号
在变量赋值时,如果值有空格,Shell会把空格后面的字符串解释为命令:
# VAR=1 2 3
-bash: 2: command not found
# VAR="1 2 3"
# echo $VAR
1 2 3
# VAR='1 2 3'
# echo $VAR
1 2 3
看不出什么区别,再举个说明:
# N=3
# VAR="1 2 $N"
# echo $VAR
1 2 3
# VAR='1 2 $N'
# echo $VAR
1 2 $N
单引号是告诉Shell忽略特殊字符,而双引号则解释特殊符号原有的意义,比如$、!。
1.7 注释
Shell注释也很简单,只要在每行前面加个#号,即表示Shell忽略解释。
第二章 Shell字符串处理之${}
上一章节讲解了为什么用${}引用变量,${}还有一个重要的功能,就是文本处理,单行文本基本上可以满足你所有需求。
2.1 获取字符串长度
# VAR='hello world!'
# echo $VAR hello world!
# echo ${#VAR}
12
2.2 字符串切片
格式:
${parameter:offset}
${parameter:offset:length}
截取从offset个字符开始,向后length个字符。
截取hello字符串:
# VAR='hello world!' # echo ${VAR:0:5} hello
截取wo字符:
# echo ${VAR:6:2} wo
截取world!字符串:
# echo ${VAR:5} world!
截取最后一个字符:
# echo ${VAR:(-1)} !
截取最后二个字符:
# echo ${VAR:(-2)}
d!
截取从倒数第3个字符后的2个字符:
# echo ${VAR:(-3):2} ld
2.3 替换字符串
格式:${parameter/pattern/string}
# VAR='hello world world!'
将第一个world字符串替换为WORLD:
# echo ${VAR/world/WORLD} hello WORLD world!
将全部world字符串替换为WORLD:
# echo ${VAR//world/WORLD} hello WORLD WORLD! 替换正则匹配为空:
# VAR=123abc
# echo ${VAR//[^0-9]/} 123
# echo ${VAR//[0-9]/} abc
patterm前面开头一个正斜杠为只匹配第一个字符串,两个正斜杠为匹配所有字符。
2.4 字符串截取
格式:
${parameter#word} # 删除匹配前缀
${parameter##word}
${parameter%word} # 删除匹配后缀
${parameter%%word}
# 去掉左边,最短匹配模式,##最长匹配模式。
% 去掉右边,最短匹配模式,%%最长匹配模式。
# URL="http://www.baidu.com/baike/user.html"
以//为分隔符截取右边字符串:
# echo ${URL#*//} www.baidu.com/baike/user.html
以/为分隔符截取右边字符串:
# echo ${URL##*/} user.html
以//为分隔符截取左边字符串:
# echo ${URL%%//*} http:
以/为分隔符截取左边字符串:
# echo ${URL%/*} http://www.baidu.com/baike
以.为分隔符截取左边:
# echo ${URL%.*}
http://www.baidu.com/baike/user
以.为分隔符截取右边:
# echo ${URL##*.} html
2.5 变量状态赋值
${VAR:-string} 如果VAR变量为空则返回string
${VAR:+string} 如果VAR变量不为空则返回string
${VAR:=string} 如果VAR变量为空则重新赋值VAR变量值为string
${VAR:?string} 如果VAR变量为空则将string输出到stderr
如果变量为空就返回hello world!:
# VAR=
# echo ${VAR:-'hello world!'} hello world!
如果变量不为空就返回hello world!:
# VAR="hello"
# echo ${VAR:+'hello world!'} hello world!
如果变量为空就重新赋值:
# VAR=
# echo ${VAR:=hello} hello # echo $VAR
hello
如果变量为空就将信息输出stderr:
# VAR=
# echo ${VAR:?value is null}
-bash: VAR: value is null
${}主要用途大概就这么多了,另外还可以获取数组元素,在后面章节会讲到。
2.6 字符串颜色
再介绍下字符串输出颜色,有时候关键地方需要醒目,颜色是最好的方式:
字体颜色 字体背景颜色 显示方式
30:黑
31:红
32:绿
33:黄
34:蓝色
35:紫色
36:深绿
37:白色 40:黑
41:深红
42:绿
43:黄色
44:蓝色
45:紫色
46:深绿
47:白色 0:终端默认设置
1:高亮显示
4:下划线
5:闪烁
7:反白显示
8:隐藏
格式:
\033[1;31;40m # 1是显示方式,可选。31是字体颜色。40m是字体背景颜色。
\033[0m # 恢复终端默认颜色,即取消颜色设置。
示例:
#!/bin/bash
# 字体颜色
for i in {31..37}; do
echo -e "\033[$i;40mHello world!\033[0m" done
# 背景颜色
for i in {41..47}; do
echo -e "\033[47;${i}mHello world!\033[0m" done
# 显示方式
for i in {1..8}; do
echo -e "\033[$i;31;40mHello world!\033[0m" done
第三章 Shell表达式与运算符
3.1 条件表达式
表达式 示例
[ expression ] [ 1 -eq 1 ]
[[ expression ]] [[ 1 -eq 1 ]]
test expression test 1 -eq 1 ,等同于[]
3.2 整数比较符
比较符 描述 示例
-eq,equal 等于 [ 1 -eq 1 ]为true
-ne,not equal 不等于 [ 1 -ne 1 ]为false
-gt,greater than 大于 [ 2 -gt 1 ]为true
-lt,lesser than 小于 [ 2 -lt 1 ]为false
-ge,greater or equal 大于或等于 [ 2 -ge 1 ]为true
-le,lesser or equal 小于或等于 [ 2 -le 1 ]为false
3.3 字符串比较符
运算符 描述 示例
== 等于 [ "a" == "a" ]为true
!= 不等于 [ "a" != "a" ]为false
> 大于,判断字符串时根据 ASCII码表顺序,不常用 在[]表达式中:[ 2 \> 1 ]为true 在[[]]表达式中:[[ 2 > 1 ]]为true 在(())表达式中:(( 3 > 2 ))为true
< 小于,判断字符串时根据 ASCII码表顺序,不常用 在[]表达式中:[ 2 \< 1 ]为false 在[[]]表达式中:[[ 2 < 1 ]]为false 在(())表达式中:(( 3 < 2 ))为false
>= 大于等于 在(())表达式中:(( 3 >= 2 ))为true
<= 小于等于 在(())表达式中:(( 3 <= 2 ))为false
-n 字符串长度不等于0为真 VAR1=1;VAR2=""
[ -n "$VAR1" ]为true
[ -n "$VAR2" ]为false
-z 字符串长度等于0为真 VAR1=1;VAR2=""
[ -z "$VAR1" ]为false
[ -z "$VAR2" ]为true
str 字符串存在为真 VAR1=1;VAR2=""
[ $VAR1 ]为true
[ $VAR2 ]为false
需要注意的是,使用-z或-n判断字符串长度时,变量要加双引号。
举例说明:
测试符 描述 示例
-e 文件或目录存在为真 [ -e path ] path存在为true
-f 文件存在为真 [ -f file_path ] 文件存在为true
-d 目录存在为真 [ -d dir_path ] 目录存在为true
-r 有读权限为真 [ -r file_path ] file_path有读权限为true
-w 有写权限为真 [ -w file_path ] file_path有写权限为true
-x 有执行权限为真 [ -x file_path ] file_path有执行权限为true
-s 文件存在并且大小大于
0为真 [ -s
为true file_path ] file_path存在并且大小大于0
3.5 布尔运算符
运算符 描述 示例
! 非关系,条件结果取反 [ ! 1 -eq 2 ]为true
-a 和关系,在[]表达式中使用 [ 1 -eq 1 -a 2 -eq 2 ]为true
-o 或关系,在[]表达式中使用 [ 1 -eq 1 -o 2 -eq 1 ]为true
3.6 逻辑判断符
判断符 描述 示例
&& 逻辑和,在[[]]和(())表达式中或判断表达式是否为真时使用 [[ 1 -eq 1 && 2 -eq 2 ]]为true
(( 1 == 1 && 2 == 2 ))为true [ 1 -eq 1 ] && echo yes 如果&&前
面表达式为true则执行后面的
|| 逻辑或,在[[]]和(())表达式中或判断表达式是否为真时使用 [[ 1 -eq 1 || 2 -eq 1 ]]为true
(( 1 == 1 || 2 == 2 ))为true [ 1 -eq 2 ] || echo yes 如果||前
面表达式为false则执行后面的
3.7 整数运算
运算符 描述
+ 加法
- 减法
* 乘法
/ 除法
% 取余
运算表达式 示例
$(()) $((1+1))
$[] $[1+1]
上面两个都不支持浮点运算。
$(())表达式还有一个用途,三目运算:
# 如果条件为真返回1,否则返回0
# echo $((1<0))
0
# echo $((1>0))
1
指定输出数字:
# echo $((1>0?1:2))
1
# echo $((1<0?1:2))
2
注意:返回值不支持字符串
3.8 其他运算工具(let/expr/bc)
除了Shell本身的算数运算表达式,还有几个命令支持复杂的算数运算:
命令 描述 示例
let 赋值并运算,支持++、-- let VAR=(1+2)*3 ; echo $VAR x=10 ; y=5
let x++;echo $x 每执行一次x加1 let y--;echo $y 每执行一次y减1 let x+=2 每执行一次x加2 let x-=2 每执行一次x减2
expr 乘法*需要加反斜杠转义\* expr 1 \* 2 运算符两边必须有空格 expr \( 1 + 2 \) \* 2 使用双括号时要转义
bc 计算器,支持浮点运算、平方等 bc本身就是一个计算器,可直接输入命令,进入解释器。
echo 1 + 2 |bc 将管道符前面标准输出作为bc的标准输入 echo "1.2+2" |bc
echo "10^10" |bc
echo 'scale=2;10/3' |bc 用scale保留两位小数点
由于Shell不支持浮点数比较,可以借助bc来完成需求:
# echo "1.2 < 2" |bc 1
# echo "1.2 > 2" |bc
0
# echo "1.2 == 2.2" |bc 0
# echo "1.2 != 2.2" |bc
1
看出规律了嘛?运算如果为真返回1,否则返回0,写一个例子:
# [ $(echo "2.2 > 2" |bc) -eq 1 ] && echo yes || echo no yes
# [ $(echo "2.2 < 2" |bc) -eq 1 ] && echo yes || echo no no
expr还可以对字符串操作:
3.9 Shell括号用途总结
看到这里,想一想里面所讲的小括号、中括号的用途,是不是有点懵逼了。那我们总结一下!
( ) 用途1:在运算中,先计算小括号里面的内容用途2:数组用途3:匹配分组
(( )) 用途1:表达式,不支持-eq这类的运算符。不支持-a和-o,支持<=、>=、<、>这类比较符和&&、|| 用途2:C语言风格的for(())表达式
$( ) 执行Shell命令,与反撇号等效
$(( )) 用途1:简单算数运算用途2:支持三目运算符 $(( 表达式?数字:数字 ))
[ ] 条件表达式,里面不支持逻辑判断符
[[ ]] 条件表达式,里面不支持-a和-o,不支持<=和>=比较符,支持-eq、<、>这类比较符。支持=~模式匹配,也可以不用双引号也不会影响原意,比[]更加通用
$[ ] 简单算数运算
{ } 对逗号(,)和点点(...)起作用,比如touch {1,2}创建1和2文件,touch {1..3}创建1、2和3文件
${ } 用途1:引用变量用途2:字符串处理
第四章 Shell流程控制
流程控制是改变程序运行顺序的指令。
4.1 if语句
格式:if list; then list; [ elif list; then list; ] ... [ else list; ] fi
4.1.1 单分支
if 条件表达式; then
命令
fi
示例:
#!/bin/bash N=10
if [ $N -gt 5 ]; then echo yes
fi
# bash test.sh yes
4.1.2 双分支
if 条件表达式; then
命令
else
命令
fi
示例1:
#!/bin/bash N=10
if [ $N -lt 5 ]; then echo yes
else echo no
fi
# bash test.sh no
示例2:判断crond进程是否运行
#!/bin/bash
NAME=crond
NUM=$(ps -ef |grep $NAME |grep -vc grep) if [ $NUM -eq 1 ]; then echo "$NAME running." else
echo "$NAME is not running!" fi
示例3:检查主机是否存活
#!/bin/bash
if ping -c 1 192.168.1.1 >/dev/null; then echo "OK."
else echo "NO!"
fi
if语句可以直接对命令状态进行判断,就省去了获取$?这一步!
4.1.3 多分支
if 条件表达式; then 命令 elif 条件表达式; then 命令
else
命令
fi
当不确定条件符合哪一个时,就可以把已知条件判断写出来,做相应的处理。
示例1:
#!/bin/bash N=$1
if [ $N -eq 3 ]; then echo "eq 3" elif [ $N -eq 5 ]; then echo "eq 5" elif [ $N -eq 8 ]; then echo "eq 8" else echo "no" fi
如果第一个条件符合就不再向下匹配。
示例2:根据Linux不同发行版使用不同的命令安装软件
#!/bin/bash
if [ -e /etc/redhat-release ]; then yum install wget -y elif [ $(cat /etc/issue |cut -d' ' -f1) == "Ubuntu" ]; then apt-get install wget -y
else
Operating system does not support. exit fi
4.2 for语句
格式:for name [ [ in [ word ... ] ] ; ] do list ; done
for 变量名 in 取值列表; do
命令
done
示例:
#!/bin/bash for i in {1..3}; do echo $i done
# bash test.sh
1
2
3
for的语法也可以这么写:
#!/bin/bash
for i in "$@"; { # $@是将位置参数作为单个来处理 echo $i
}
# bash test.sh 1 2 3
1
2
3
默认for循环的取值列表是以空白符分隔,也就是第一章讲系统变量里的$IFS:
#!/bin/bash for i in 12 34; do echo $i done
# bash test.sh
12
34
如果想指定分隔符,可以重新赋值$IFS变量:
#!/bin/bash
OLD_IFS=$IFS IFS=":"
for i in $(head -1 /etc/passwd); do echo $i done
IFS=$OLD_IFS # 恢复默认值
# bash test.sh root x
0 0 root
/root
/bin/bash
for循环还有一种C语言风格的语法,常用于计数、打印数字序列:
for (( expr1 ; expr2 ; expr3 )) ; do list ; done
#!/bin/bash
for ((i=1;i<=5;i++)); do # 也可以i-- echo $i done
示例1:检查多个主机是否存活
#!/bin/bash
for ip in 192.168.1.{1..254}; do if ping -c 1 $ip >/dev/null; then echo "$ip OK." else echo "$ip NO!" fi done
示例2:检查多个域名是否可以访问
#!/bin/bash
URL="www.baidu.com www.sina.com www.jd.com" for url in $URL; do
HTTP_CODE=$(curl -o /dev/null -s -w %{http_code} http://$url) if [ $HTTP_CODE -eq 200 -o $HTTP_CODE -eq 301 ]; then echo "$url OK." else echo "$url NO!" fi done
4.3 while语句
格式:while list; do list; done
while 条件表达式; do
命令
done
示例1:
#!/bin/bash N=0
while [ $N -lt 5 ]; do
let N++ echo $N
done
# bash test.sh
1
2
3
4 5
当条件表达式为false时,终止循环。示例2:条件表达式为true,将会产生死循环
#!/bin/bash while [ 1 -eq 1 ]; do echo "yes" done
也可以条件表达式直接用true:
#!/bin/bash while true; do echo "yes" done
还可以条件表达式用冒号,冒号在Shell中的意思是不做任何操作。但状态是0,因此为true:
#!/bin/bash while :; do echo "yes" done
示例3:逐行处理文本文本内容:
# cat a.txt a b c 1 2 3 x y z
要想使用while循环逐行读取a.txt文件,有三种方式:方式1:
#!/bin/bash
cat ./a.txt | while read LINE; do
echo $LINE done
方式2:
#!/bin/bash while read LINE; do echo $LINE done < ./a.txt
方式3:
#!/bin/bash
exec < ./a.txt # 读取文件作为标准输出
while read LINE; do echo $LINE done
与while关联的还有一个until语句,它与while不同之处在于,是当条件表达式为false时才循环,实际使用中比较少,这里不再讲解。
4.4 break和continue语句
break是终止循环。
continue是跳出当前循环。
示例1:在死循环中,满足条件终止循环
#!/bin/bash N=0
while true; do let N++
if [ $N -eq 5 ]; then
break fi echo $N
done
# bash test.sh
里面用了if判断,并用了break语句,它是跳出循环。与其关联的还有一个continue语句,它是跳出本次循环。
示例2:举例子说明continue用法
#!/bin/bash N=0
while [ $N -lt 5 ]; do
let N++
if [ $N -eq 3 ]; then continue fi echo $N
done
# bash test.sh
当变量N等于3时,continue跳过了当前循环,没有执行下面的echo。
注意:continue与break语句只能循环语句中使用。
4.5 case语句
case语句一般用于选择性来执行对应部分块命令。
格式:case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac
case 模式名 in 模式1) 命令 ;; 模式2) 命令
;;
*)
不符合以上模式执行的命令 esac
每个模式必须以右括号结束,命令结尾以双分号结束。
示例:根据位置参数匹配不同的模式
#!/bin/bash case $1 in start) echo "start."
;; stop)
echo "stop." ;; restart)
echo "restart."
;; *)
echo "Usage: $0 {start|stop|restart}" esac
# bash test.sh
Usage: test.sh {start|stop|restart}
# bash test.sh start start.
# bash test.sh stop stop.
# bash test.sh restart restart.
上面例子是不是有点眼熟,在Linux下有一部分服务启动脚本都是这么写的。
模式也支持正则,匹配哪个模式就执行那个:
#!/bin/bash case $1 in [0-9])
echo "match number."
;; [a-z])
echo "match letter."
;;
'-h'|'--help') echo "help"
;; *)
echo "Input error!" exit esac
# bash test.sh 1 match number. # bash test.sh a match letter. # bash test.sh -h help
# bash test.sh --help help
模式支持的正则有:*、?、[ ]、[.-.]、|。后面有章节单独讲解Shell正则表达式。
4.6 select语句
select是一个类似于for循环的语句。
格式:select name [ in word ] ; do list ; done
select 变量 in 选项1 选项2; do
break done
示例:
#!/bin/bash
select mysql_version in 5.1 5.6; do
echo $mysql_version
done
# bash test.sh
1) 5.1
2) 5.6
#? 1 5.1
#? 2
5.6
用户输入编号会直接赋值给变量mysql_version。作为菜单用的话,循环第二次后就不再显示菜单了,并不能满足需求。
在外面加个死循环,每次执行一次select就break一次,这样就能每次显示菜单了:
#!/bin/bash while true; do
select mysql_version in 5.1 5.6; do
echo $mysql_version
break
done done
# bash test.sh
1) 5.1
2) 5.6
#? 1
5.1
1) 5.1
2) 5.6
#? 2
5.6
1) 5.1
2) 5.6
如果再判断对用户输入的编号执行相应的命令,如果用if语句多分支的话要复杂许多,用case语句就简单多了。
#!/bin/bash
PS3="Select a number: " while true; do
select mysql_version in 5.1 5.6 quit; do case $mysql_version in
5.1)
echo "mysql 5.1"
break
;; 5.6)
echo "mysql 5.6"
break ;; quit) exit
;; *)
echo "Input error, Please enter again!" break esac
done done
# bash test.sh
1) 5.1
2) 5.6
3) quit
Select a number: 1 mysql 5.1 1) 5.1
2) 5.6
3) quit
Select a number: 2 mysql 5.6 1) 5.1
2) 5.6
3) quit
Select a number: 3
如果不想用默认的提示符,可以通过重新赋值变量PS3来自定义。这下就比较完美了!
第五章 Shell函数与数组
5.1 函数
格式:
func() { command
}
function关键字可写,也可不写。示例1:
#!/bin/bash func() {
echo "This is a function."
} func
# bash test.sh
This is a function.
Shell函数很简单,函数名后跟双括号,再跟双大括号。通过函数名直接调用,不加小括号。
示例2:函数返回值
#!/bin/bash func() {
VAR=$((1+1)) return $VAR
echo "This is a function."
} func echo $? # bash test.sh
2
return在函数中定义状态返回值,返回并终止函数,但返回的只能是0-255的数字,类似于exit。
示例3:函数传参
#!/bin/bash func() {
echo "Hello $1"
}
func world # bash test.sh
Hello world
通过Shell位置参数给函数传参。
函数也支持递归调用,也就是自己调用自己。
例如:
#!/bin/bash test() { echo $1 sleep 1 test hello
} test
执行会一直在调用本身打印hello,这就形成了闭环。
像经典的fork炸弹就是函数递归调用:
:(){ :|:& };: 或 .(){.|.&};.
这样看起来不好理解,我们更改下格式:
:() {
:|:&
};
:
再易读一点:
bomb() { bomb|bomb&
}; bomb
分析下:
:(){ } 定义一个函数,函数名是冒号。
: 调用自身函数
| 管道符
: 再一次递归调用自身函数
:|: 表示每次调用函数":"的时候就会生成两份拷贝。
& 放到后台
; 分号是继续执行下一个命令,可以理解为换行。
: 最后一个冒号是调用函数。
因此不断生成新进程,直到系统资源崩溃。
一般递归函数用的也少,了解下即可!
5.2 数组
数组是相同类型的元素按一定顺序排列的集合。
格式:
array=(元素1 元素2 元素3 ...)
用小括号初始化数组,元素之间用空格分隔。
定义方法1:初始化数组 array=(a b c)
定义方法2:新建数组并添加元素 array[下标]=元素
定义方法3:将命令输出作为数组元素 array=($(command)) 数组操作:
获取所有元素:
# echo ${array[*]} # *和@ 都是代表所有元素 a b c
获取元素下标:
# echo ${!a[@]}
0 1 2
获取数组长度:
# echo ${#array[*]}
3
获取第一个元素:
# echo ${array[0]} a
获取第二个元素:
# echo ${array[1]} b
获取第三个元素:
# echo ${array[2]} c
添加元素:
# array[3]=d # echo ${array[*]} a b c d
添加多个元素:
# array+=(e f g) # echo ${array[*]} a b c d e f g
删除第一个元素:
# unset array[0] # 删除会保留元素下标
# echo ${array[*]} b c d e f g
删除数组:
# unset array
数组下标从0开始。
示例1:讲seq生成的数字序列循环放到数组里面
#!/bin/bash
for i in $(seq 1 10); do array[a]=$i let a++
done echo ${array[*]}
# bash test.sh
1 2 3 4 5 6 7 8 9 10
示例2:遍历数组元素
方法1:
#!/bin/bash
IP=(192.168.1.1 192.168.1.2 192.168.1.3) for ((i=0;i<${#IP[*]};i++)); do
echo ${IP[$i]}
done
# bash test.sh
192.168.1.1
192.168.1.2
192.168.1.3
方法2:
#!/bin/bash
IP=(192.168.1.1 192.168.1.2 192.168.1.3)
for IP in ${IP[*]}; do
echo $IP done
第六章 Shell正则表达式
正则表达式在每种语言中都会有,功能就是匹配符合你预期要求的字符串。
Shell正则表达式分为两种:
基础正则表达式:BRE(basic regular express)
扩展正则表达式:ERE(extend regular express),扩展的表达式有+、?、|和() 下面是一些常用的正则表达式符号,我们先拿grep工具举例说明。
符号 描述 示例
. 匹配除换行符(\n)之外的任意单个字符 匹配123:
echo -e "123\n456" |grep '1.3'
^ 匹配前面字符串开头 匹配以abc开头的行:
echo -e "abc\nxyz" |grep ^abc
$ 匹配前面字符串结尾 匹配以xyz结尾的行:
echo -e "abc\nxyz" |grep xyz$
* 匹配前一个字符零个或多个 匹配x、xo和xoo:
echo -e "x\nxo\nxoo\no\noo" |grep "xo*"
x是必须的,批量了0零个或多个
+ 匹配前面字符1个或多个 匹配abc和abcc:
echo -e "abc\nabcc\nadd" |grep -E 'ab+' 匹配单个数字:echo "113" |grep -o '[0-9]'
连续匹配多个数字:echo "113" |grep -E -o '[0-
9]+'
? 匹配前面字符0个或1个 匹配ac或abc:
echo -e "ac\nabc\nadd" |grep -E 'a?c'
[ ] 匹配中括号之中的任意一个字符 匹配a或c:
echo -e "a\nb\nc" |grep '[ac]'
[ .-.] 匹配中括号中范围内的任意一个字符 匹配所有字母:
echo -e "a\nb\nc" |grep '[a-z]'
[^] 匹配[^字符]之外的任意一个字符 匹配a或b:
echo -e "a\nb\nc" |grep '[^c-z]' 匹配末尾数字:echo "abc:cde;123" |grep -E '[^;]+$'
^[^] 匹配不是中括号内任意一个字符开头的行 匹配不是#开头的行:
grep '^[^#]' /etc/httpd/conf/httpd.conf
{n}或
{n,} 匹配花括号前面字符至少n 个字符 匹配abc字符串(至少三个字符以上字符串):
echo -e "a\nabc\nc" |grep -E '[a-z]{3}'
{n,m} 匹配花括号前面字符至少n 个字符,最多m个字符 匹配12和123(不加边界符会匹配单个字符):
echo -e "1\n12\n123\n1234" |grep -E -w -o '[0-
9]{2,3}'
\< 边界符,匹配字符串开始 匹配开始是123和1234:
echo -e "1\n12\n123\n1234" |grep '\<123'
\> 边界符,匹配字符串结束 匹配结束是1234:
echo -e "1\n12\n123\n1234" |grep '4\>'
( ) 单元或组合:将小括号里面作为一个组合分组:匹配小括号中正则表达式或字符。\n反向引用,n是数字,从1开始编 单元:匹配123a字符串
echo "123abc" |grep -E -o '([0-9a-z]){4}'
分组:匹配11
echo "113abc" |grep -E -o '(1)\1'
匹配出现xo出现零次或多次:
echo -e "x\nxo\nxoo\no\noo" |egrep "(xo)*"
号,表示引用第n个分组匹配的内容
| 匹配竖杠两边的任意一个 匹配12和123:
echo -e "1\n12\n123\n1234" |grep -E '12\>|123\>'
\ 转义符,将特殊符号转成原有意义 1.2,匹配1.2:1\.2,否则112也会匹配到
Posix字符 描述
[:alnum:] 等效[a-zA-Z0-9]
[:alpha:] 等效[a-zA-Z]
[:lower:] 等效[a-z]
[:upper:] 等效[A-Z]
[:digit:] 等效[0-9]
[:space:] 匹配任意空白字符,等效[\t\n\r\f\v]
[:graph:] 非空白字符
[:blank:] 空格与定位字符
[:cntrl:] 控制字符
[:print:] 可显示的字符
[:punct:] 标点符号字符
[:xdigit:] 十六进制
示例:
echo -e "1\n12\n123\n1234a" |grep '[[:digit:]]'
在Shell下使用这些正则表达式处理文本最多的命令有下面几个工具:
命令 描述
grep 默认不支持扩展表达式,加-E选项开启ERE。如果不加-E使用花括号要加转义符\{\}
egrep 支持基础和扩展表达式
awk 支持egrep所有的正则表达式
sed 默认不支持扩展表达式,加-r选项开启ERE。如果不加-r使用花括号要加转义符\{\}
支持的特殊字符 描述
\w 匹配任意数字和字母,等效[a-zA-Z0-9_]
\W 与\w相反,等效[^a-zA-Z0-9_]
\b 匹配字符串开始或结束,等效\<和\>
\s 匹配任意的空白字符
\S 匹配非空白字符
空白符 描述
\n 换行符
\r 回车符
\t 水平制表符
\v 垂直制表符
\0 空值符
\b 退后一格