Shell脚本学习笔记
shell脚本
概述
shell是一个命令行解释器,它接收应用程序\用户命令,然后调用操作系统内核
解释器负责将用户的指令翻译为内核可以识别的指令
shell还是一个功能相当强大的编程语言,易编写,易调试,灵活性强
shell脚本
提前将可执行的命令语句写入一个文件
快捷键
常用快捷键:
Tab
键补齐命令ctrl+A
光标到命令的最前面ctrl+E
光标到命令的最后面hostory
命令历史alias
命令别名- 标准输入与输出重定向
(>、>>、2>、2>>、&>)
- 管道
(|)
编写shell脚本
1 |
|
sh 脚本文件名 会启动子进程
source 脚本文件名 # 不会启动子进程
各类括号的作用
单小括号()
- 命令组合 括号中的命令会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格。
- 命令替换 shell扫描一遍命令行发现$(ls)结构,便将里面的ls执行一次,得到其标准输出,有些shell不支持,如tcsh
- 用于初始化数组。如a=(a b c)
双小括号(())
常用于算数运算比较,双括号中的变量可以不使用$符号前缀,括号内支持多个表达式用分号;隔开。括号中的表达式需要符合c语言运算规则,比如for循环 for ((i=1;i>10;i++))
。再如if (($i<10))
如果不使用双括号,则为if [ $i -lt 10 ]
中括号[]
- 单中括号,bash的内部命令,与test相同。
- 双中括号
- 是bash程序语言的关键字,并不是一个命令,双中括号比单中括号的结构更加通用,在双中括号中所有的字符都不会发生文件名扩展或者单词分割,但是会发生参数和命令替换。
- 支持字符串模式匹配,使用=~操作符时甚至支持shell正则表达式,字符串比较时可以把右边作为一个模式,而不仅仅是一个字符串,比如[[ hello == hell?]],结果为真,[[]]中匹配字符串或通配符,不需要引号。
- 使用双括号条件判断结构,能够防止脚本中许多逻辑错误,比如&&,||操作符能够正常存在于[[]]条件判断结构中,但是如果出现在单中括号中会报错,比如可以直接使用
if [[ $a -ne 1 && $a -ne 2 ]]
,如果不使用单括号则为if [ $a -ne 1 ]&&[ $a -ne 2 ]
或者if [ $a -ne 1 -a $a -ne 2 ]
- bash中把双括号中的表达式看作一个单独的元素,并返回一个退出状态码
大括号
常规用法
- 大括号拓展。(通配(globbing))将对大括号中的文件名做扩展。在大括号中,不允许有空白,除非这个空白被引用或转义。第一种:对大括号中的以逗号分割的文件列表进行拓展。如 touch {a,b}.txt 结果为a.txt b.txt。第二种:对大括号中以点点(..)分割的顺序文件列表起拓展作用,如:touch {a..d}.txt 结果为a.txt b.txt c.txt d.txt
- 代码块,又被称为内部组,这个结构事实上创建了一个匿名函数 。与小括号中的命令不同,大括号内的命令不会新开一个子shell运行,即脚本余下部分仍可使用括号内变量。括号内的命令间用分号隔开,最后一个也必须有分号。{}的第一个命令和左括号之间必须要有一个空格。
符号$后的括号
- $(a)变量a的值,在不引起歧义的情况下可以省略大括号
- $(ls -l)命令替换,如docker中
docker rm $(docker ps -qa)
批量删除所有容器 - $(())用于获得计算结果。
echo $((3-2))
变量
以固定的名称,存放可以能有变化的值
定义变量的格式:
变量名=变量值
取消变量的格式
unset 变量名
注意事项:
- =两边不能有空格,不要使用关键字做变量名。
- 如果变量名已经存在则覆盖之前的变量值。
- 变量名称有:字母/数字/下划线组成,不能以数字开始,不可以使用特殊字符。
查看变量的语法格式:
$变量名
${变量名}
可以使用echo打印出来变量的值
使用unset 变量名取消变量
环境变量
变量名通常大写,有操作系统维护
环境变量存储在/etc/profile或~/.bash_profile
命令env
可以列出所有环境变脸
常见的环境变量有:
1 | PATH |
位置变量
bash内置变量,存储脚本执行时的参数
使用$n
表示,n为数字序列号
在$1~$9代表第1~9参数,10和10以上的参数需要用大括号包含,如${10}
$1,$2,$3,…,${10},${11},…
预定义变量
bash内置变量,可以调用但是不能赋值或修改
用来保存脚本程序的执行信息
直接使用这些变量
不能为这些变量赋值
变量名 | 含义 |
---|---|
$0 | 表示当前所在的进程或脚本名 |
$$ | 当前运行进程的PID |
$? | 命令执行后的返回状态,0表示正常,1或其他表示异常 |
$# | 已加载的位置变量的个数 |
$* | 所有位置变量的值 |
自定义变量
用户自主设置的变量
变量名=值
变量的扩展及应用
各类引号的作用
shell脚本中我们常用的有三种引号,双引号,单引号,反引号
双引号" ":允许扩展,以$引用其他变量
单引号' ': 禁用扩展,及时$引用也视作普通字符
反引号` `: 将命令的执行输出作为变量值,$()与反引号等效
read命令定义变量
read从键盘读入变量值完成赋值
格式:read -p "提示信息" 变量名
选项:
- -p 提示信息
- -t 指定超时秒数
- -s 设置是否在终端显示输入的内容
全局变量和局部变量
局部变量:新定义的变量默认只在当前shell中有效,无法在子shell环境中使用
全局变量:全局变量在当前shell及子shell和未来开启的子shell环境中均有效
1 | 变量名=值 |
运算
整数运算
四则运算:
- 加法:num1 + num2
- 减法:num1 - num2
- 乘法:num1 * num2
- 整除:num1 / num2
取余数运算:
- 求余数:num1 % num2
使用$[]和$(())表达式
语法格式:
1 | $[整数1 运算符 整数2] |
完整表达式 | 简写表达式 |
---|---|
i=i+1 | i++ |
i=i-1 | i– |
i=i+2 | i+=2 |
i=i-2 | i-=2 |
i=i*2 | i*=2 |
i=i/2 | i/=2 |
i=i%2 | i%=2 |
小数运算
- bash内仅支持整数运算,不支持小数运算
- 我们可以通过计算器软件bc实现小数运算
如果没有该软件需要安装。centos系统安装方法
1 | yum install -y bc |
bc支持交互式和非交互式两种方式计算,scale=n
可以约束小数位
交互式运算直接bc回车就可以
非交互式计算
1 | [root@yyt ~]# echo "1.2+1.1" |bc |
bc 支持比较操作符:>、>=、<、<=、==、!=
表达式成立则返回1,否则返回0
条件测试
语法格式:
- test 选项 参数
- [选项 参数] (日后推荐使用这种)
字符串的比较
1 | # 注意使用[]是选项和参数的两边都必须要有一个空格存在 |
整数值比较
1 | [ 整数值1 操作符 整数值2 ] |
操作符 | 含义 |
---|---|
-eq | 等于 |
-ne | 不等于 |
-ge | 大于或等于 |
-le | 小于或等于 |
-gt | 大于 |
-lt | 小于 |
文件目录状态测试
1 | [ 操作符 文件或目录] |
操作符 | 含义 |
---|---|
-e | 判断文件或目录是否存在,若存在则结果为真 |
-d | 判断对象是否为目录,是则为真 |
-f | 判断对象是否为普通文件,是则为真 |
-r | 判断文件或目录是否有可读权限,是则为真 |
-w | 判断文件或目录是否有可写权限,是则为真 |
-x | 对象是否有可执行权限,是则为真 |
控制操作符
使用控制符组合多个命令
1 | ; |
监控脚本
tr -s
删除多余重复的字串(如空格)
1 | ls | tr -s " " |
cut命令过滤数据
cut -d "以什么分隔" -f数字(第几个)
1 | cut -d ":" -f1 /etc/passwd |
if语句
单分支
语法格式:
1 | # 第一种写法 |
双分支
1 | if 条件测试;then |
当条件成立时执行命令序列1,否则执行命令序列2
多分支
1 | if 条件判断1;then |
当条件判断1满足就会执行then后面的命令序列1.如果不满足则否则去判断条件判断2.在不满足就是3,全部不满足了执行else里面的命令序列n。
for循环
根据变量的不同取值,重复执行命令序列
1 | for 变量 in 值列表 |
值列表可以是一个值,或多个值。循环多少次取决于值列表里面有多少值。
1 | for ((初值;条件;步长)) |
while循环
1 | while 条件测试 |
反复测试条件,只要成立就执行命令序列
简单的例子
1 | # 只要i小于等于1000就让他一直打印yyt |
case语句
检查,判断变量的取值
- 功能类似于多分之的if语句
- 如果与预设的值相匹配,则执行对应的操作
- 命令序列最后必须以分号结尾
1 | case 变量 in |
命令序列可以打很多个命令,但是需要注意如果只有一条命令,必须使用双分号结尾,如果有多条命令,那么最后一条命令必须以双分号结尾。
双分号是结束符
示例
获取输入,输入redhat返回fedora,输入fedora返回redhat,输入其它,返回必须输入指定要求的内容
1 |
|
在case语句中的模式)前还可以写
1 | Y|y|yes|YES) |
数组
数组也是一个变量,是一个有点特殊的变量
存储多个数据的集合就是数组
1 | [root@yyt ~]# a1=(11 22 33) #定义一个数组 |
shell函数
在shell环境中,将一些需要重复使用的操作操作,定义为公共的语句块,讲某一段代码取一个名称就是函数。
语法格式1
1 | function 函数名{ |
语法格式2
1 | 函数名(){ |
调用已定义的函数
格式:
函数名
函数传值
- 格式:
函数名
值1 值2 … - 传递的值作为函数的”位置参数”
- 格式:
示例
1 | [root@yyt ~]# imsg(){ |
另一种格式
1 | [root@yyt ~]# function msg{ |
输出颜色
1 |
|
多进程版ping
中断与退出
- continue 可以结束单次循环
- break可以结束循环体
- exit可以退出脚本
字符串的处理和变量初始化
字符串的处理
字符串的截取
语法格式:
1 | ${变量:起始位置:长度} |
示例:
1 | [root@yyt ~]# s=1234567 |
字符串的替换
替换一个结果
${变量/旧字符/新字串}
替换全部结果
${变量//旧字串/新字串}
字符串掐头
字符串去尾
批量更改扩展名
## 变量初始化原变量有值,返回该变量的值
原变量无值,返回初始值
语法格式
1 | ${变量:-关键词} |
1 | [root@yyt ~]# a=123 |
随机密码
1 | # 环境变量 |
正则表达式
grep语法格式
1 | grep 选项 匹配模式 文件 |
描述一个字符集合的表达方式
模糊匹配
正则符号 | 描述 |
---|---|
abc | 匹配abc |
^ | 匹配开头 |
$ | 匹配结尾 |
[集合] | 匹配集合中的任意单个字符 |
[^集合] | 对集合取反 |
. | 代表任意单个字符 |
* | 匹配前一个字符任意次(包含0次) |
.* | 匹配任意长度的任意字符 |
\{n,m\} | 匹配前一个字符n到m次 |
\{n,\} | 匹配前一个字符至少n次 |
\{n\} | 匹配前一个字符n次 |
例如
1 | grep "[0-9]\{3,4}" |
扩展正则
就是把基本正则给简化了
正则符号 | 描述 |
---|---|
+ | 匹配前面的字符至少一次 |
? | 匹配前面的字符0或1次 |
() | 组合与保留 |
| | 或者 |
{n,m} | 匹配前面的字符n到m次 |
{n,} | 匹配前面的字符至少n次 |
{n} | 匹配前面的字符n次 |
注意:grep默认不支持扩展正则需要加上-E
参数。
Perl兼容正则
特点都是以右斜线开头
正则符号 | 描述 |
---|---|
\b | 匹配单词边界 |
\w | 匹配字符数字下划线 |
\W | 和\w相反 |
\s | 匹配空白 |
\d | 匹配数字 |
\d+ | 匹配多个数字 |
\D | 匹配非数字 |
注意:默认的grep不支持perl正则需要加上-P
参数
\b的示例
sed基础
流式编辑器
- 非交互式
- 逐行处理
- 可以文本进行增删改查等操作
语法格式
1 | sed [选项] '[定位符]指令' 文件名 |
常用命令选项
命令选项 | 描述 |
---|---|
-n | 使用安静模式,加上-n 选项后,只有经过sed特殊处理的那一行才会被列出来。 |
-e | 允许在该选项后添加一条新的编辑指令,当有多条编辑指令,时应该使用该选项逐一添加。 |
-i | 直接修改读取文件内容,而不是由屏幕输出。(常用) |
-r | 支持扩展正则表达式。 |
-f | 直接将sed的操作写在一个文件内,-f 文件名 即可执行文件里面的sed操作 |
-h | 输出sed的帮助信息 |
数据定位
行号定位
sed可以使用行号;来定位自己需要修改的数据内容
1 | sed -n '3p' # 打印第3行 |
正则定位
sed可以使用正则匹配需要的数据,然后再编辑对应的内容。
操作子命令
操作子命令指示
sed
对指定行进行何种操作,包括打印,删除,修改等。
命令 | 描述 |
---|---|
p | 打印输出被选中的行 |
d | 删除被选中的行 |
a 字符串 | 将字符串单独作为一行追加到被选中的行之后 |
c 字符串 | 将选中的行替换替换为字符串 |
i 字符串 | 在被选中的行之前插入字符串。 |
s/字符串1/字符串2/标志 | 查找替换,通常s 可以搭配正则表达式,将字符串1替换为字符串2 |
r 文件名 | 在选中的行之后追加文件的内容。 |
w 文件名 | 将选择的行内容写入文件。 |
= | 打印当前行号 |
子命令d:删除行演示
以etc下面的passwd文件为例
注意,这里只是演示时临时删除并没有真正删除
删除所有行
1
cat -n /etc/passwd |sed 'd'
删除第一行
1
2
3
4
5
6
7[root@yyt ~]# cat -n /etc/passwd |sed '1d'
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown删除第2行到最后一行
1
2[root@yyt ~]# cat -n /etc/passwd |sed '2,$d'
1 root:x:0:0:root:/root:/bin/bash
子命令a:追加内容
子命令
a
表示在指定行下边
插入指定行的内容。
在/etc/hosts每行之下后插入一行,内容为A
1
2
3
4
5
6
7
8
9
10
11[root@yyt ~]# cat -n /etc/hosts |sed 'a A'
1 ::1 localhost
A
2 127.0.0.1 localhost
A
3
A
4 172.25.101.112 yyt yyt
A
5
A在/etc/hosts第一行之下插入1行,内容为A
1
2
3
4
5
6
7[root@yyt ~]# cat -n /etc/hosts |sed '1a A'
1 ::1 localhost
A
2 127.0.0.1 localhost
3
4 172.25.101.112 yyt yyt
5在/etc/hosts第一行之下插入多行,内容用\n换行符换行
1
2
3
4
5
6
7
8
9[root@yyt ~]# cat -n /etc/hosts |sed '1a A\nB\nC'
1 ::1 localhost
A
B
C
2 127.0.0.1 localhost
3
4 172.25.101.112 yyt yyt
5
子命令i:插入内容
子命令
i
和a
功能类似,只不过是在指定行上边插入指定行的内容。
在/etc/hosts第1行之上插入1行,内容为A
1
2
3
4
5
6
7[root@yyt ~]# cat -n /etc/hosts |sed '1i A'
A
1 ::1 localhost
2 127.0.0.1 localhost
3
4 172.25.101.112 yyt yyt
5
子命令c:内容替换
c
是表示把指定行内容替换为自己需要的行内容
将/etc/hosts中每行的内容都替换为A
1
2
3
4
5
6[root@yyt ~]# cat -n /etc/hosts |sed 'c A'
A
A
A
A
A将/etc/hosts中第一行的内容替换为A
1
2
3
4
5
6[root@yyt ~]# cat -n /etc/hosts |sed '1c A'
A
2 127.0.0.1 localhost
3
4 172.25.101.112 yyt yyt
5
子命令s:替换内容
子命令
s
为替换子命令,是sed命令使用频率最高的子命令,没有之一,因为支持正则表达式,所有功能变得强大无比
基本语法:s/模式/替换字符串/标志
注意:/
可以换成其它的符号。
子命令s
支持的标志如下。
g
:全局更改。n
:可以是1-512,表示第n次出现的情况进行替换w 文件名
:写入到一个文件file中。