文本处理和shell脚本基础
正则表达式和文本处理
正则表达式(Regular Expression)是用于描述一组字符串特征的模式,用来匹配特定的字符串。通过特殊字符(元字符)+普通字符来进行模式描述,从而达到文本匹配目的工具。
正则表达式的元字符分类:字符匹配、匹配次数、位置锚定、分组
1. 基础正则表达式元字符
1.1常用元字符
. 匹配任意单个字符,可以是一个汉字
[] 匹配指定范围内的任意单个字符,示例:[wang] [0-9] [a-z] [a-zA-Z]
[^] 匹配指定范围外的任意单个字符,示例:[^wang]
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]包含的范围广
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
\w #匹配单词构成部分,等价于[_[:alnum:]]
\W #匹配非单词构成部分,等价于[^_[:alnum:]]
\S #匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\s #匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意Unicode 正则表达式会匹配全角空格符
1.2 匹配次数
用在要指定次数的字符后面,用于指定前面字符出现的次数
* #匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.* #任意长度的任意字符
\? #匹配其前面的字符出现0次或1次,即:可有可无
\+ #匹配其前面的字符出现最少1次,即:肯定有且 >=1 次
\{n\} #匹配前面的字符n次
\{m,n\} #匹配前面的字符至少m次,至多n次
\{,n\} #匹配前面的字符至多n次,<=n
\{n,\} #匹配前面的字符至少n次
1.3 位置锚定
用于定位字符出现的位置
^ #行首锚定, 用于模式的最左侧
$ #行尾锚定,用于模式的最右侧
^PATTERN$ #用于模式匹配整行
^$ #空行
^[[:space:]]*$ #空白行
\< 或 \b #词首锚定,用于单词模式的左侧
\> 或 \b #词尾锚定,用于单词模式的右侧
\<PATTERN\> #匹配整个单词
#注意: 单词是由字母,数字,下划线组成
1.4 分组和其他
1.4.1 分组
分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名
方式为: \1, \2, \3, ...
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
1.4.2 或者
或者:\|
2. 扩展正则表达式元字符
2.1 字符匹配
. 任意单个字符
[wang] 指定范围的字符
[^wang] 不在指定范围的字符
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
2.2 匹配次数
* 匹配前面字符任意次
? 0或1次
+ 1次或多次
{n} 匹配n次
{m,n} 至少m,至多n次
2.3 位置锚定
^ 行首
$ 行尾
\<, \b 语首
\>, \b 语尾
2.4 分组和其他
2.4.1 分组
() 分组
后向引用:\1, \2, ...
2.4.2
| 或者
a|b #a或b
C|cat #C或cat
(C|c)at #Cat或cat
- 正则示例
3.1 匹配IP地址
[root@centos8 ~]# ip a| grep brd|grep -Eo '([0-9]{,3}\.){3}[0-9]{,3}'|grep -Ev '255$'
10.0.0.18
3.2 匹配/etc/fstab中#开头的行
[root@centos8 ~]# grep -E '^#' /etc/fstab
#
# /etc/fstab
# Created by anaconda on Sun Nov 21 08:06:01 2021
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
3.3 匹配/etc/passwd中nologin结尾的行
[root@centos8 ~]# grep -E 'nologin$' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin
systemd-resolve:x:193:193:systemd Resolver:/:/sbin/nologin
tss:x:59:59:Account used for TPM access:/dev/null:/sbin/nologin
polkitd:x:998:996:User for polkitd:/:/sbin/nologin
unbound:x:997:994:Unbound DNS resolver:/etc/unbound:/sbin/nologin
sssd:x:996:993:User for sssd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:995:992::/var/lib/chrony:/sbin/nologin
文本处理
- 文本处理之VI
VI是Linux中功能强大的文本处理工具,是一个模式编辑器,VIM是VI的增强版
1.1 VIM命令
vim [OPTION]... FILE...
常用选项
+# 打开文件后,让光标处于第#行的行首,+默认行尾
+/PATTERN 让光标处于第一个被PATTERN匹配到的行行首
-b file 二进制方式打开文件
-d file1 file2… 比较多个文件,相当于 vimdiff
-m file 只读打开文件
-e file 直接进入ex模式,相当于执行ex file
-y file Easy mode (like "evim", modeless),直接可以操作文件,ctrl+o:wq|q保存和不保存退出
1.2 三种主要模式和模式转换
三种常见模式:
命令或普通(Normal)模式:默认模式,可以实现移动光标,剪切/粘贴文本
插入(Insert)或编辑模式:用于修改文本
扩展命令(extended command )或命令(末)行模式:保存,退出等
模式转换:
命令模式 --> 插入模式
i insert, 在光标所在处输入
I 在当前光标所在行的行首输入
a append, 在光标所在处后面输入
A 在当前光标所在行的行尾输入
o 在当前光标所在行的下方打开一个新行
O 在当前光标所在行的上方打开一个新行
插入模式 --- ESC-----> 命令模式
命令模式 ---- : ----> 扩展命令模式
扩展命令模式 ----ESC,enter----> 命令模式
1.2 扩展命令模式
按“:”进入Ex模式 ,创建一个命令提示符: 处于底部的屏幕左侧
1.2.1 扩展命令模式基本命令
w 写(存)磁盘文件
wq 写入并退出
x 写入并退出
X 加密
q 退出
q! 不存盘退出,即使更改都将丢失
r filename 读文件内容到当前文件中
w filename 将当前文件内容写入另一个文件
!command 执行命令
r!command 读入命令的输出
1.2.2 地址定界
定位到指定位置,常用格式:
# #具体第#行,例如2表示第2行
#,# #从左侧#表示起始行,到右侧#表示结尾行
#,+# #从左侧#表示的起始行,加上右侧#表示的行数,范例:2,+3 表示2到5行
. #当前行
$ #最后一行
.,$-1 #当前行到倒数第二行
% #全文, 相当于1,$
/pattern/ #从当前行向下查找,直到匹配pattern的第一行,即:正则表达式
/pat1/,/pat2/ #从第一次被pat1模式匹配到的行开始,一直到第一次被pat2匹配到的行结束
#,/pat/ #从指定行开始,一直找到第一个匹配pattern的行结束
/pat/,$ #向下找到第一个匹配patttern的行到整个文件的结尾的所有行
注:地址定界之后跟一个编辑命令,表示对定界范围内的内容进行操作,常用的命令有:
d #删除
y #复制
w file #将范围内的行另存至指定文件中
r file #在指定位置插入指定文件中的所有内容
1.2.3 查找并替换
对查找到的内容进行替换
格式
s/要查找的内容/替换为的内容/修饰符
要查找的内容:可使用基本正则表达式模式
替换为的内容:不能使用模式,但可以使用\1, \2, ...等后向引用符号;还可以使用“&”引用前面查找时查找到的整个内容
修饰符:
i #忽略大小写
g #全局替换,默认情况下,每一行只替换第一次出现
gc #全局替换,每次替换前询问
注:在特殊情况下可用#,@作为分隔符,简化命令
1.3 VIM命令行模式
光标移动使用箭头或者hjkl四个字母
h (左) j (下) k (上) l (右)
从shell开始启动vim的命令是:vim 文件名 <ENTER>
退出VIM:
放弃所有更改退出: <ESC> :q! <ENTER> .
保存更改退出: <ESC> :wq <ENTER> .
删除光标处的字符: x
插入字符:
在光标之前插入字符: i
小写字母 o 在当前行的下方插入一个空白行,并进入编辑模式
大写字母 O 在当前行的上方插入一个空白行,并进入编辑模式
小写字母 a 要在光标的后面插入字符.
大写字母 A 要在该行的末尾添加字符
注意:按<ESC>键可以让你回到正常模式或者取消你未完成的命令
删除字符,从光标开始直到遇到下一个单词 dw
删除字符,从光标开始直到当前行的末尾 d$
删除一整行 dd
重复一个动作,可以在动作之前加一个数字: 2w
一些操作的格式是:
操作符 [数字] 移动
操作符:要做什么,例如字母d是用于删除
数字: 你要重复的次数
移动: 你的操作要作用在多少文本内容上,例如w就是一个单词,$是到行尾
把光标移动到行首: 0
撤销之前的动作: u (小写u)
撤销这一行的所有改动: U (大写U)
撤销刚才的”撤销“: CTRL-R
打印出你刚刚删除的内容: p
它会把内容打印在你光标的后面
喜欢光标位置的字符:先输入r,然后输入新的字符
改动类操作符可以让你改变从当前光标到”motion“的位置
ce 可以改变从光标到单词的末尾
c$ 可以改变从光标都行末尾
改动类操作的格式是:
c [数字] 移动
移动到文件末尾: G
移动到某一行: 行号 G
移动到第一行 gg
前向搜索,输入 / 然后紧跟你要搜索的字符串,
后向搜索,输入 ?
输入 n 来找到下一个出现的地方
输入 N 来找到上一个出现的地方
CTRL-O可以回到之前的编辑的位置
CTRL-I可以跳到新的位置
输入 % 来跳转到与之匹配的括号,当光标在 ( ) [ ] { }
替换改行的第一个old单词为new
:s/old/new
替换改行的所有old单词为new
:s/old/new/g
替换两个#之间的单词
:#,#s/old/new/g
替换文件中所有的单词
:%s/old/new/g
每一个替换之前都需要确认的话,在命令末尾加一个 c
:%s/old/new/gc
:!命令 会执行一个外部命令
:!ls 列出目录
:!rm FILE 删除文件
:w 文件名 把当前vim文件另存为某个文件名
:r FILENAME 从某个文件中取出内容添加到当前的位置
:r !cmd 把命令的结果添加到光标的位置
e 移动到单词的末尾
y操作符 用来拷贝文本, p 用来粘贴
大写字母 R 进入 替换模式,直到按下<ESC>键
":set xxx"来设置选项 "xxx", 举例选项如下:
'ic' 'ignorecase' 搜索的时候忽略大写小写
'is' 'incsearch' 在输入搜索目标字符串的时候实时匹配并显示
'hls' 'hlsearch' 高亮匹配项
- 文本处理三剑客之grep
grep 命令主要对文本的(正则表达式)行基于模式进行过滤
命令格式:
grep [OPTIONS] PATTERN [FILE...]
常见选项:
-color=auto 对匹配到的文本着色显示
-m # 匹配#次后停止
-v 显示不被pattern匹配到的行,即取反
-i 忽略字符大小写
-n 显示匹配的行号
-c 统计匹配的行数
-o 仅显示匹配到的字符串
-q 静默模式,不输出任何信息
-A # after, 后#行
-B # before, 前#行
-C # context, 前后各#行
-e 实现多个选项间的逻辑or关系,如:grep –e ‘cat ' -e ‘dog' file
-w 匹配整个单词
-E 使用ERE,相当于egrep
-F 不支持正则表达式,相当于fgrep
-f file 根据模式文件处理
-r 递归目录,但不处理软链接
-R 递归目录,但处理软链接
范例:
- 取分区利用率
[root@centos8 ~]# df -h |grep -Eo '[0-9]{,3}%'|grep -Eo '[[:alnum:]]+'
0
0
2
0
3
1
19
0
- 取passwd文件中root字符串
[root@centos8 ~]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
- operator:x:11:0:operator:/root:/sbin/nologin
[root@centos8 ~]# grep -E '^root' /etc/passwd
root:x:0:0:root:/root:/bin/bash
- 其他常见文本处理工具
3.1 文本查看
3.1.1 查看文本内容
cat 可以查看文本内容
命令格式:
cat [OPTION]... [FILE]...
常用选项:
-E:显示行结束符$
-A:显示所有控制符
-n:对显示出的每一行进行编号
-b:非空行编号
-s:压缩连续的空行成一行
3.1.2 分页查看文件内容
3.1.2.1 more
可以实现分页查看文件,可以配合管道实现输出信息的分页
命令格式
more [OPTIONS...] FILE...
3.1.2.2 less
less 也可以实现分页查看文件或STDIN输出,less 命令是man命令使用的分页器
3.1.3 显示文本前或后行内容
3.1.3.1 head
可以显示文件或标准输入的前面行
命令格式:
head [OPTION]... [FILE]...
常用选项:
-c # 指定获取前#字节
-n # 指定获取前#行,#如果为负数,表示从文件头取到倒数第#前
-# 同上
3.1.3.2 tail
tail 和head 相反,查看文件或标准输入的倒数行
命令格式:
tail [OPTION]... [FILE]...
常用选项:
-c # 指定获取后#字节
-n # 指定获取后#行,如果#是负数,表示从第#行开始到文件结束
-# 同上
-f 跟踪显示文件fd新追加的内容,常用日志监控,相当于 --follow=descriptor,当文件删除再新建同名文件,将无法继续跟踪文件
-F 跟踪文件名,相当于--follow=name --retry,当文件删除再新建同名文件,将可以继续跟踪文件
tailf 类似 tail –f,当文件不增长时并不访问文件,节约资源,CentOS8无此工具
3.2 按列抽取文本
cut 命令可以提取文本文件或STDIN数据的指定列
命令格式:
cut [OPTION]... [FILE]..
常用选项:
-d DELIMITER: 指明分隔符,默认tab
-f FILEDS:
#: 第#个字段,例如:3
#,#[,#]:离散的多个字段,例如:1,3,6
#-#:连续的多个字段, 例如:1-6
混合使用:1-3,7
-c 按字符切割
--output-delimiter=STRING指定输出分隔符
3.3 合并多个文件
paste 合并多个文件同行号的列到一行
命令格式:
paste [OPTION]... [FILE]...
常用选项
-d #分隔符:指定分隔符,默认用TAB
-s #所有行合成一行显示
3.4 分析文本的工具
3.4.1收集文本统计数据
wc 命令可用于统计文件的行总数、单词总数、字节总数和字符总数
可以对文件或STDIN中的数据统计
命令格式:
wc file
cmd | wc -l
常用选项:
-l 只计数行数
-w 只计数单词总数
-c 只计数字节总数
-m 只计数字符总数
-L 显示文件中最长行的长度
3.4.2 文本排序
sort把整理过的文本显示在STDOUT,不改变原始文件
命令格式:
sort [options] file(s)
常用选项:
-r 执行反方向(由上至下)整理
-R 随机排序
-n 执行按数字大小整理
-h 人类可读排序,如: 2K 1G
-f 选项忽略(fold)字符串中的字符大小写
-u 选项(独特,unique),合并重复项,即去重
-t c 选项使用c做为字段界定符
-k # 选项按照使用c字符分隔的 # 列来整理能够使用多次
3.4.3 去重
uniq命令从输入中删除前后相接的重复的行
命令格式:
uniq [OPTION]... [FILE]...
常用选项:
-c: 显示每行重复出现的次数
-d: 仅显示重复过的行
-u: 仅显示不曾重复的行
3.5 文本处理范例
1.分页,从前面行,从后面行查看文本内容
[root@centos8 data]# man cat |more
[root@centos8 data]# man cat |less
查看前两行
[root@centos8 data]# cat fstab |head -n2
查看后两行
[root@centos8 data]# cat fstab |tail -n2
2.查看文件并统计
a) 统计行数
[root@centos8 data]# cat fstab |wc -l
b) 统计字符数
[root@centos8 data]# cat fstab |wc -c
- 去除指定列,排序
a) 取列
[root@centos8 data]# df -h |tr -s " "|tail -n +2|cut -d" " -f 5 #取出利用率
b) 排序
对利用率进行排序
[root@centos8 data]# df -h |tr -s " "|tail -n +2|cut -d" " -f 5 |sort -h
Shell脚本编程
Shell脚本基础
- shell脚本用法
1.1 脚本结构
shell脚本编程:是基于过程式、解释执行的语言
编程语言的基本结构:
各种系统命令的组合
数据存储:变量、数组
表达式:a + b
控制语句:if
shell脚本:包含一些命令或声明,并符合一定格式的文本文件
格式要求:首行shebang机制
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
1.2 脚本创建
第一步:使用文本编辑器来创建文本文件
第一行必须包括shell声明序列:#!
第二步:加执行权限
给予执行权限,在命令行上指定脚本的绝对或相对路径
第三步:运行脚本
直接运行解释器,将脚本作为解释器程序的参数运行
- shell脚本的变量
2.1 变量基础
变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据
变量类型:
内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE
用户自定义变量
不同的变量存放的数据不同,决定了以下
数据存储方式
参与的运算
表示的数据范围
变量数据类型:
字符
数值:整型、浮点型,bash 不支持浮点数
2.2 变量命名,定义和引用
2.2.1 变量命名
命名要求
区分大小写
不能使程序中的保留字和内置变量:如:if, for
只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
命名习惯
见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
变量名大写
局部变量小写
函数名小写
大驼峰StudentFirstName
小驼峰studentFirstName
下划线: student_name
2.3 变量定义和引用
变量的生效范围等标准划分变量类型
普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell
进程均无效
环境变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片断,通常指函数
变量赋值:
name='value'
value 可以是以下多种形式
直接字串:name='root'
变量引用:name="$USER"
命令引用:name=`COMMAND` 或者 name=$(COMMAND)
注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除
变量引用:
$name
${name}
弱引用和强引用
"$name " 弱引用,其中的变量引用会被替换为变量值
'$name ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
- 环境变量和位置变量
3.1 环境变量
环境变量:
可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
一般只在系统配置文件中使用,在脚本中较少使用
变量声明和赋值:
#声明并赋值
export name=VALUE
declare -x name=VALUE
#或者分两步实现
name=VALUE
export name
3.2 位置变量
位置变量:在bash shell中内置的变量, 在脚本代码中调用通过命令行传递给脚本的参数
$1, $2, ... 对应第1个、第2个等参数,shift [n]换位置
$0 命令本身,包括路径
$* 传递给脚本的所有参数,全部参数合为一个字符串
$@ 传递给脚本的所有参数,每个参数为独立字符串
$# 传递给脚本的参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异
- 算术运算
Shell允许在某些情况下对算术表达式进行求值,比如:let和declare 内置命令,(( ))复合命令和算术扩展。求值以固定宽度的整数进行,不检查溢出,尽管除以0 被困并标记为错误。运算符及其优先级,关联性和值与C语言相同。以下运算符列表分组为等优先级运算符级别。级别按降序排列优先。
4.1 算数运算的实现
实现算术运算:
(1) let var=算术表达式
(2) ((var=算术表达式)) 和上面等价
(3) var=$[算术表达式]
(4) var=$((算术表达式))
(5) var=$(expr arg1 arg2 arg3 ...)
(6) declare -i var = 数值
(7) echo '算术表达式' | bc
4.2 随机数和增强赋值
生成随机数:$RANDOM 取值范围:0-32767
生成指定范围随机数 echo $[$RANDOM%范围]
增强赋值:
+= i+=10 相当于 i=i+10
-= i-=j 相当于 i=i-j
*=
/=
%=
++ i++,++i 相当于 i=i+1
-- i--,--i 相当于 i=i-1
- 逻辑运算
5.1 与运算
与:&:和0相与结果为0,和1相与结果保留原值, 一假则假,全真才真
0 与 0 = 0
0 与 1 = 0
1 与 0 = 0
1 与 1 = 1
5.2 或运算
或:|:和1相或结果为1,和0相或结果保留原值,一真则真,全假才假
0 或 0 = 0
0 或 1 = 1
1 或 0 = 1
1 或 1 = 1
5.3 非
非:!
! 1 = 0 ! true
! 0 = 1 ! false
5.4 异或
异或的两个值,相同为假,不同为真。两个数字X,Y异或得到结果Z,Z再和任意两者之一X异或,将得出 另一个值Y
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
5.5短路运算
短路与 &&
CMD1 短路与 CMD2
第一个CMD1结果为真 (1),第二个CMD2必须要参与运算,才能得到最终的结果
第一个CMD1结果为假 (0),总的结果必定为0,因此不需要执行CMD2
短路或 ||
CMD1 短路或 CMD2
第一个CMD1结果为真 (1),总的结果必定为1,因此不需要执行CMD2
第一个CMD1结果为假 (0),第二个CMD2 必须要参与运算,才能得到最终的结果
- 条件测试
6.1 变量测试
#判断 NAME 变量是否定义
[ -v NAME ]
#判断 NAME 变量是否定义并且是名称引用,bash 4.4新特性
[ -R NAME ]
6.2 数值测试
-eq 是否等于
-ne 是否不等于
-gt 是否大于
-ge 是否大于等于
-lt 是否小于
-le 是否小于等于
注:当用(())对数值进行比较时
== 相等
!= 不相等
<=
>=
<
>
6.3 字符串测试
test和 [ ]用法
test和 [ ]用法
-z STRING 字符串是否为空,没定义或空为真,不空为假,
-n STRING 字符串是否不空,不空为真,空为假
STRING 同上
STRING1 = STRING2 是否等于,注意 = 前后有空格
STRING1 != STRING2 是否不等于
> ascii码是否大于ascii码
< 是否小于
[[]] 用法
[[ expression ]] 用法
== 左侧字符串是否和右侧的PATTERN相同
注意:此表达式用于[[ ]]中,PATTERN为通配符
=~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
注意: 此表达式用于[[ ]]中;扩展的正则表达式
6.4 文件测试
存在性测试
a FILE:同 -e
-e FILE: 文件存在性测试,存在为真,否则为假
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件
- 组合测试和其他相关用法
COMMAND1 && COMMAND2 #并且,短路与,代表条件性的AND THEN
如果COMMAND1 成功,将执行COMMAND2,否则,将不执行COMMAND2
COMMAND1 || COMMAND2 #或者,短路或,代表条件性的OR ELSE
如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2
! COMMAND #非,取反
- Bash shell相关配置文件
全局配置:针对所有用户皆有效
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
个人配置:只针对特定用户有效
~/.bash_profile
~/.bashrc
流程控制
- 条件判断
a) If
语法:
if 判断条件; then 判断为真执行语句; [ elif 判断条件2; then 判断2为真执行语句; ]... [ else 条件为假执行; ] fi
if判断分为单分支,双分支和多分支,
单分支:执行一次判断,条件为真执行语句后结束,条件为假则直接结束
if cmd ;then cmd; fi
双分支:if和else,当条件为真执行判断为真的执行语句,其他则执行else下执行语句
If cmd1 ;then cmd1;else cmd; fi
多分支:if elif 和else配合使用,进行多次判断,并依据条件执行不同的语句
If cmd1 ;then cmd1 elif cmd2 ;then cmd2 else cmd3 fi
b) Case
语法:
case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
case支持glob风格的通配符:
* 任意长度任意字符
? 任意单个字符
[] 指定范围内的任意单个字符
| 或者,如: a|b
- 循环
a) For
以此将列表内的元素取出按照循环体内指定操作进行循环,直到列表内元素耗尽
语法:
for NAME [in WORDS ... ] ; do COMMANDS; done
#方式1
for 变量名 in 列表;do
循环体
done
#方式2
for 变量名 in 列表
do
循环体
Done
注:在shell内也可使用c风格的for循环格式
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do
循环体
done
b) While
语法:
while COMMANDS; do COMMANDS; done
while CONDITION; do
循环体
Done
说明:循环开始之前先对CMMANDS做一次判断,当判断为真时执行循环体,为假则退出
注意:while循环一定要设置退出条件,否则会变成死循环:while true;do cmd done
c) Until
语法:
until COMMANDS; do COMMANDS; done
until CONDITION; do
循环体
Done
说明:until跟while类似,当判断为假时执行循环体,注意死循环情况
- 循环控制
a) Continue[N]
循环内嵌套判断,在判断条件为真执行内容中添加continue则跳过本轮循环直接进入下一次,N表示第几层循环默认为1即当前循环
while CONDITION1; do
CMD1
...
if CONDITION2; then
continue
fi
CMDn
...
done
b) Break[N]
循环内嵌套判断,在判断条件为真执行内容中添加break则结束本轮循环,N表示第几层循环默认为1即当前循环
while CONDITION1; do
CMD1
...
if CONDITION2; then
break
fi
CMDn
...
done
函数
- 函数基础
函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程
它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一
部分
函数和shell程序区别
Shell程序在子Shell中运行
函数在当前Shell中运行。因此在当前Shell中,函数可对shell中变量进行修改
- 函数管理
函数由两部分组成:函数名和函数体
2.1定义函数
#语法一:
func_name (){
...函数体...
}
#语法二:
function func_name {
...函数体...
}
#语法三:
function func_name () {
...函数体...
}
2.2查看函数
#查看当前已定义的函数名
declare -F
#查看当前已定义的函数定义
declare -f
#查看指定当前已定义的函数名
declare -f func_name
#查看当前已定义的函数名定义
declare -F func_name
2.3删除函数
unset func_name
- 函数调用
函数的调用方式
可在交互式环境下定义函数
可将函数放在脚本文件中作为它的一部分
可放在只包含函数的单独文件中
调用:函数只有被调用才会执行,通过给定函数名调用函数,函数名出现的地方,会被自动替换为函数
代码
函数的生命周期:被调用时创建,返回时终止
说明:函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用,调用 函数仅使用其函数名即可
数组
- 数组基础
变量:存储单个元素的内存空间
数组:存储多个元素的连续的内存空间,相当于多个变量的集合
数组名和索引
索引的编号从0开始,属于数值索引
索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash 4.0版本之后开始支持
bash的数组支持稀疏格式(索引不连续)
1.1 声明数组
普通数组可以不事先声明,直接使用
declare -a ARRAY_NAME
关联数组必须先声明,再使用
declare -A ARRAY_NAME
1.2 数组赋值
数组元素的赋值
(1) 一次只赋值一个元素
ARRAY_NAME[INDEX]=VALUE
(2) 一次赋值全部元素
ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
(3) 只赋值特定元素
ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
(4) 交互式数组值对赋值
read -a ARRAY
1.3 引用数组
1.3.1 引用特定的数组元素
${ARRAY_NAME[INDEX]}
#如果省略[INDEX]表示引用下标为0的元素
1.3.2 引用数组所有元素
${ARRAY_NAME[*]}
${ARRAY_NAME[@]}
1.3.3 数组的长度,即数组中元素的个数
${#ARRAY_NAME[*]}
${#ARRAY_NAME[@]}
1.3.4 删除数组
使用unset命令可对数组进行删除操作
unset ARRAY[INDEX] #按索引删除
unset ARRAY #整个删除
1.3.5 数组数据处理
1.3.5.1 数组切片
${ARRAY[@]:offset:number}
- offset #要跳过的元素个数
number #要取出的元素个数
#取偏移量之后的所有元素
{ARRAY[@]:offset}
1.3.5.2 追加元素
ARRAY[${#ARRAY[*]}]=value
ARRAY[${#ARRAY[@]}]=value
1.3.6 关联数组
默认数组索引为数字,关联数组是指定非数字为索引
declare -A ARRAY_NAME
ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2‘...)
注意:关联数组必须先声明再调用
字符串处理
a) 基于偏移量取字符串
#返回字符串变量var的字符的长度,一个汉字算一个字符
${#var}
#返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,
- offset的取值在0 到 ${#var}-1 之间(bash4.2后,允许为负值)
${var:offset}
#返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,长度为number的部分
${var:offset:number}
#取字符串的最右侧几个字符,取字符串的最右侧几个字符, 注意:冒号后必须有一空白字符
${var: -length}
#从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容,即:掐头去尾
${var:offset:-length}
#先从最右侧向左取到length个字符开始,再向右取到距离最右侧offset个字符之间的内容,注意:-
length前空格,并且length必须大于offset
${var: -length:-offset}
b) 基于模式取子串
#其中word可以是指定的任意字符,功能:自右而左,查找var变量所存储的字符串中,第一次出现的word,
删除字符串最后一个字符向左至第一次出现word字符串(含)之间的所有字符,即懒惰模式,以从右向左的第
一个word为界删右留左
${var%word*}
#同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符,即贪婪模式,以从右向
左的最后一个word为界删右留左
${var%%word*}
#其中word可以是指定的任意字符,功能:自右而左,查找var变量所存储的字符串中,第一次出现的word,
删除字符串最后一个字符向左至第一次出现word字符串(含)之间的所有字符,即懒惰模式,以从右向左的第
一个word为界删右留左
${var%word*}
#同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符,即贪婪模式,以从右向
左的最后一个word为界删右留左
${var%%word*}
c) 查找替换
#查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替换之
${var/pattern/substr}
#查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substr替换之
${var//pattern/substr}
#查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substr替换之
${var/#pattern/substr}
#查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substr替换之
${var/%pattern/substr}
d) 查找并删除
#删除var表示的字符串中第一次被pattern匹配到的字符串
${var/pattern}
删除var表示的字符串中所有被pattern匹配到的字符串
${var//pattern}
删除var表示的字符串中所有以pattern为行首匹配到的字符串
${var/#pattern}
删除var所表示的字符串中所有以pattern为行尾所匹配到的字符串
${var/%pattern}
e) 字符大小写转换
#把var中的所有小写字母转换为大写
${var^^}
#把var中的所有大写字母转换为小写
${var,,}
范例
1、 统计出/etc/passwd文件中其默认shell为非/sbin/nologin的用户个数,并将用户都显示出来
[root@centos8 data]# awk -F"[:/]" '{if( $NF != "nologin" ){BASH[$1]++;print $1}}END{print length(BASH)}' /etc/passwd
root
sync
shutdown
halt
named
5
2、 查出用户UID最大值的用户名、UID及shell类型
[root@centos8 data]# awk -F":" '{if(num <= $3){num=$3}else if(num>$3){num=num}}END{print $1,$3,$7,num}' /etc/passwd
named 25 /bin/false 65534
3、 统计当前连接本机的每个远程主机IP的连接数,并按从大到小排序
[root@centos8 data]# ss -nt | grep "^ESTAB" |tr -s ' ' : |cut -d: -f6|sort |uniq -c|sort -nr
1 10.0.0.1
4、 编写脚本disk.sh,显示当前硬盘分区中空间利用率最大的值
[root@centos8 data]# vim disk.sh
df |grep -E '^/dev' |grep -E '[0-9]{,3}%'|sort|head -n1
5、 编写脚本 systeminfo.sh,显示当前主机系统信息,包括:主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小
[root@centos8 data]# vim systeminfo.sh
#!/bin/bash
name=`hostname`
ip=`ip a| grep brd|grep -Eo '([0-9]{,3}\.){3}[0-9]{,3}'|grep -Ev '255$'`
sysname=`cat /etc/os-release |grep -E '^NAME='|awk -F'"| ' '{print $2}'`
version=`cat /etc/os-release |grep -E '^VERSION_ID'|awk -F'"| ' '{print $2}'`
kernel=`uname -r`
cpu=`lscpu |grep -E '^Model name' |tr -s " "|awk -F ":|@" '{print $2}'`
mem=`free -h |tr -s " "|awk -F" " '/Mem/{print $2}'`
disk=`fdisk -l |grep "Disk /dev/" |awk -F ":|," '{print $2}'`
echo "主机名:${name}"
echo "ip地址:${ip}"
echo "系统:${sysname} ${version}"
echo "内核:${kernel}"
echo "cpu:${cpu}"
echo "内存:${mem}"
echo "硬盘:${disk}"
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下