在Linux中我们经常编辑修改文本文件, 即由ASCl, Unicode 或其它编码的纯文字的文件。之前介绍过nano, 实际
工作中我们会使用更为专业, 功能强大的工具
文本编辑种类:
全屏编辑器: nano(字符工具), gedit(图形化工具), vi, vim
行编辑器: sed
vi: Visual editor, 文本编辑器, 是Linux 必备工具之一, 功能强大, 学习曲线较陡峭, 学习难度大
vim:Visual editor iMproved, 和vi 使用方法一致, 但功能更为强大, 不是必备软件
官网: www.vim.org
其他相关编辑器: gvim 一个Vim编辑器的图形版本
vim[OPTION]...FILE...
+ 打开文件后, 让光标处于第 # 行的行首, +默认行尾
+ /PATTERN 让光标处于第一个被PATTERN匹配到的行行首
-b file 二进制方式打开文件
-d file1 file2... 比较多个文件,相当于 vimdiff
-m file 只读打开文件
-e file 直接进入ex模式,相当于执行ex file
说明:
如果该文件存在,文件被打开并显示内容
如果该文件不存在,当编辑后第一次存盘时创建它
vim 是一个模式编辑器,击键行为是依赖于vim的的“模式”
三种常见模式:
命令模式-- > 插入模式
i insert, 在光标所在处输入
I 在当前光标所在行的行首输入
a append, 在光标所在处后面输入
A 在当前光标所在行的行尾输入
o 在当前光标所在行的下方打开一个新行
O 在当前光标所在行的上方打开一个新行
插入模式----ESC---- > 命令模式
命令模式----: ---- > 扩展命令模式
扩展命令模式----ESC, enter---- > 命令模式
按: 进入Ex模式, 创建一个命令提示符: 处于底部的屏幕左侧
w 写(存)磁盘文件
wq 写入并退出
x 写入并退出
X 加密。取消密码:不输入任何字符直接保存
q 退出
q!不存盘退出,即使更改都将丢失
r filename 读文件内容到当前文件中 如 :r filename 回车就可以将文件内容直接加入进去光标后
w filename 将当前文件内容写入另一个文件
!cmd 不更换窗口或关闭vim就可执行命令(不可是别名)
r!cmd 读入命令的输出到光标后
: start_pos, end_pos cmd
具体第 # 行,例如2表示第2行
, # 从左侧 # 表示起始行,到右侧 # 表示结尾行
, + # 从左侧 # 表示的起始行,加上右侧 # 表示的行数,范例: 2, +3 表示2到5行
.当前行
$ 最后一行
., $ - 1 当前行到倒数第二行
% 全文,相当于1, $
地址定界后跟一个编辑命令cmd:
d 删除
y 复制
w file 将范围内的行另存至指定文件中
r file 在指定位置插入指定文件中的所有内容
例:: 2, 4 d 即删除2 - 4行
: 2, 3y 即复制2 + 3行,中间有空行另 +
复制后,按p加到光标后,大写P加到光标前
/pattern/从当前行向下查找,直到匹配pattern的第一行, 即: 正则表达式
/pat1/, /pat2/从第一次被pat1模式匹配到的行开始,一直到第一次被pat2匹配到的行结束
, /pat/从指定行开始,一直找到第一个匹配patttern的行结束
/pat/, $ 向下找到第一个匹配patttern的行到整个文件的结尾的所有行
格式
s / 要查找的内容 / 替换为的内容 / 修饰符
要查找的内容:可使用正则表达式模式
替换为的内容:不能使用模式,但可以使用 \ 1, \ 2, …等后向引用符号,还可以使用 & 引用前面查找时查找到的整个内容
修饰符:
如: 1, 4s / root / babe / g 将1 - 4行的root全部修改为babe,不加g只修改一行中的第一个
: % s / root / babe / g 修改所有的root为babe
说明: 查找替换中的分隔符 / 可替换为其它字符, 如: # , @ , 这对于修改目录或文件时有用, 避免出现很多 /
配置文件: 永久有效
全局: /etc/vimrc
个人: ~ / .vimrc
扩展命令模式: 当前vim进程有效
显示: set number,简写 set nu
取消显示: set nonumber, 简写 set nonu
启用: set ignorecase,简写 set ic
不忽略: set noic
启用: set autoindent,简写 set ai
禁用: set noai
启用: set paste
禁用: set nopaste
启用: set list
禁用: set nolist
启用: set hlsearch
禁用: set nohlsearch
启用: syntax on
禁用: syntax off
启用windows格式: set fileformat = dos
启用unix格式: set fileformat = unix
简写 set ff = dosunix
set textwidth = 65(vim only)
set wrapmargin = 15
启用: set cursorline,简写 set cul
禁用: set nocursorline
启用: set key = password
禁用: set key =
set 帮助
: help option - list
: set a
命令模式功能强大,又称为Normal模式,只是按键时屏幕看不到输入,所以需要大量的记忆才能更好的使用。
Zz 保存退出
ZQ 不保存退出
字符间跳转:
h: 左 L: 右 j: 下 k: 上
CMD: 跳转由 # 指定的个数的字符
单词间跳转:
w: 下一个单词的词首
e: 当前或下一单词的词尾
b: 当前或前一个单词的词首
CMD: 由 # 指定一次跳转的单词数
当前页跳转:
H: 页首 M: 页中间行 L: 页底
zt: 将光标所在当前行移到屏幕顶端
zz: 将光标所在当前行移到屏幕中间
zb: 将光标所在当前行移到屏幕底端
行首行尾跳转:
^ 跳转至行首的第一个非空白字符
0 跳转至行首
$ 跳转至行尾
行间移动:
跳转至由第 # 行。或者扩展命令模式下:
G 最后一行
1G, gg 第一行
句间移动: )下一句(上一句 :用.隔开的句子
段落间移动:
}
下一段
}
上一段 :用一整行空行隔开的句子
命令模式翻屏操作:
Ctrl + f 向文件尾部翻一屏
Ctrl + b 向文件首部翻一屏
Ctrl + d 向文件尾部翻半屏
Ctrl + u 向文件首部翻半屏
x 剪切光标处的字符
x 剪切光标处起始的 # 个字符
xp 交换光标所在处的字符及其后面字符的位置,即剪切后粘贴
~转换大小写
J 删除当前行后的换行符
r 替换光标所在处的一个字符,即按下一个字符
R 切换成REPLACE模式(在最下面显示REPLACE), 按ESC回到命令模式
d 剪切命令,可结合光标跳转字符,实现范围剪切
d$ 剪切到行尾
d ^ 剪切除到非空行首
d0 剪切到行首
dw 剪切至 下一个单词的词首
de 剪切至 当前或下一个单词的词尾
db 剪切至 当前或前一个单词的词首
CMD
dd 剪切光标所在的行
dd 多行剪切
D 从当前光标位置一直剪切到行尾,等同于d$
y 复制,行为相似于d命令
y$ 复制到行尾
y ^ 复制除到非空行首
y0 复制到行首
yw 复制至 下一个单词的词首
ye 复制至 当前或下一个单词的词尾
yb 复制至 当前或前一个单词的词首
yy 复制行
yy 复制多行
Y 复制整行
p 缓冲区存的如果为整行,则粘贴当前光标所在行的下方;否则,粘贴至当前光标所在处的后面
P 缓冲区存的如果为整行,则粘贴当前光标所在行的上方;否则,粘贴至当前光标所在处的前面
c 删除后切换成插入模式
c$
c ^
c0
cw
ce
cb
cy
CMD
cc 删除当前行并进入插入模式输入新内容,相当于S
cc
C 删除当前光标到行尾,并切换成插入模式, 相当于c$
/PATTERN or /string从当前光标所在处向文件尾部查找
? PATTERN or / string 从当前光标所在处向文件首部查找
n 与命令同方向找下一个
N 与命令反方向找下一个
u 撤销最近的更改, 相当于win里ctrl + z
u 撤销之前多次更改
U 撤消光标落在这行后所有此行的更改
Ctrl - r 重做最后的“撤消”更改, 相当于win里ctrl + y
.重复前一个操作
.重复前一个操作 # 次
< start position > < CMD > < end position >
常见CMD : y复制、d 删除、gU 变大写、gu 变小写
范例:
0y$ 从行首拷贝到行尾
di " 光标在" "之间,则删除" "之间的内容 (可以使用其他括号)
yi( 光标在()之间,则复制()之间的内容
vi[ 光标在[]之间,则选中[]之间的内容
vi{ 光标在{}之间,则选中{}之间的内容
dtx 删除字符直到遇见光标之后的第一个 x 字符
ytx 复制字符直到遇见光标之后的第一个 x 字符
在末行有"–VISUAL–"指示,表示在可视化模式
允许选择的文本块
可视化键可用于与移动键结合使用
w ) } 箭头等
突出显示的文字可被删除,复制,变更,过滤,搜索,替换等
范例:在文件行首插入#
输入ctrl+v 进入可视化模式
输入 G 跳到最后1行,选中每一行的第一个字符
输入 I 切换至插入模式
输入 # 在行首插入#
按 ESC 键 使全部行首都插入#
vim FILE1 FILE2 FILE3 ...
:next 下一个
:prev 前一个
:first 第一个
:last 最后一个
:wall 保存所有
:qall 不保存退出所有
:wqall 保存退出所有
vim -o|-O FILE1 FILE2 ...
-o: 水平或上下分
-o: 垂直或左右分割 (vim only)
在窗口间切换: Ctrl+w,Arrow
Ctrl+w,s split, 水平分割,上下分屏
Ctrl+w,v vertical,垂直分割,左右分屏
ctrl+w,q 取消相邻窗口
ctrl+w,o 取消全部窗口
:wqall 保存退出
有26个命名寄存器和1个无命名寄存器,常存放不同的剪贴版内容,可以在同一个主机的不同会话(终端窗口)间共享
寄存器名称a,b,…,z,
格式 " 寄存器 放在数字和命令之间
范例:
3 "tyy 表示复制3行到t寄存器中,未行显示3 lines yanked into " t
"tp 表示将t寄存器内容粘贴
若未指定,将使用无命名寄存器
有10个数字寄存器,用0,1,…,9表示,0存放最近复制内容,1存放最近删除内容。当新的文本变更和删除时,1转存到2,2转存到3,以此类推。数字寄存器不能在不同会话间共享
ma 将当前位置标记为a,26个字母均可做标记, mb 、mc 等等
'a 跳转到a标记的位置,实用的文档内标记方法,文档中跳跃编辑时很有用
qa 录制宏a,a为宏的名称,未行提示: recording @a
q 停止录制宏
@a 执行宏 a
@@ 重新执行上次执行的宏
1以二进制方式打开文件 vim -b binaryfile
2扩展命令模式下,利用xxd命令转换为可读的十六进制 :%!xxd
3切换至插入模式下,编辑二进制文件
4切换至扩展命令模式下,利用xxd命令转换回二进制 :%!xxd -r
5保存退出
:help
:help topic
Use :q to exit help
或命令vimtutor直接打开vim的帮助
cat 可以查看文本内容
格式:
cat [OPTION]...[FILE]...
常见选项
-E: 显示待结束符$
-A: 显示所有控制符
-n: 对显示出的每一行进行编号,包括空行
-b: 非空行才加编号
-s: 压缩连续的空行成一行
tac [filename] 逆向显示文本内容 ,和下面均支持标准输入
nl [filename] 显示行号,相当于cat -b
rev [filename] 将同一行的内容逆向显示
例:
#echo {a..z} | tr -d ' ' |hexdump -C
00000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 |abcdefghijklmnop|
00000010 71 72 73 74 75 76 77 78 79 7a 0a |qrstuvwxyz.|
0000001b
od = dump files in octal and other formats
例:
#echo {a..z} | tr -d ' ' |od -t x
0000000 64636261 68676665 6c6b6a69 706f6e6d
0000020 74737271 78777675 000a7a79
0000033
#echo {a..z} | tr -d ' ' |od -t x1
0000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70
0000020 71 72 73 74 75 76 77 78 79 7a 0a
0000033
#echo {a..z} | tr -d ' ' |od -t x1z
0000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 >abcdefghijklmnop<
0000020 71 72 73 74 75 76 77 78 79 7a 0a >qrstuvwxyz.<
0000033
例:
#echo {a..z} | tr -d ' ' |xxd
00000000: 6162 6364 6566 6768 696a 6b6c 6d6e 6f70 abcdefghijklmnop
00000010: 7172 7374 7576 7778 797a 0a qrstuvwxyz.
可以实现分页查看文件,可以配合管道实现输出信息的分页
格式
more [OPTIONS...] FILE..
选项:
-d: 显示翻页及退出提示
less 也可以实现分页查看文件或STDIN输出
查看时有用的命令包括
/文本搜索文本
n/N 跳到下一个 或 上一个匹配
注意:more只能向下翻,且到100%即阅读完时,将自动退出文件的查看
less命令是man命令使用的分页器
less
head 可以显示文件或标准输入的前面行,默认前10行
格式:
head [OPTION]...[FILE]..
选项:
-C# 指定获取前#字节
-n# 指定获取前#行
-# 同上
例:
#head -n 5 /etc/passwd 查看passwd的前五行
root:x:0:0:root:/root:/bin/bash
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
#ls /etc/ -lS |head -5 将etc下的文件降序排序后查看前5个最大的文件
total 1412
-rw-r--r--. 1 root root 692252 May 15 2020 services
-rw-r--r--. 1 root root 60352 May 11 2017 mime.types
-rw-r--r--. 1 root root 44379 Jul 10 20:05 ld.so.cache
-rw-r--r--. 1 root dnsmasq 26843 Aug 10 2021 dnsmasq.conf
tail 和head 相反,查看文件或标准输入的倒数行
格式:
tai1 [OPTION]... [FILE]...
-C# 指定获取后#字节
-n# 指定获取后#行
-# 同上
-f 跟踪显示文件fd新追加的内容,常用日志监控,相当于 --foow=descriptor,当文件删除再新建同名文件,将无法继续跟踪文件
-F 跟踪文件名,相当于--follow=name --retry,当文件删除再新建同名文件,将可以继续跟踪文件
tailf 类似tail -f,当文件不增长时并不访问文件
例:
#tail -fn0或-0f /var/log/messages 从0开始跟踪messages文件的日志生成,即最新生成的日志
#ifconfig ens160 |head -2|tail -1 准确找到inconfig的ip地址的那一行的数据显示
inet 10.0.0.201 netmask 255.255.255.0 broadcast 10.0.0.255
注意:一次性命令不可跟踪,如dmesg,执行一次就退出。
ping也不可以,无法显示出来**
cut 命令可以提取文本文件或STDIN数据的指定列
格式
cut [OPTION]...[FILE]...
选项
-d DELIMITER: 指明分隔符,默认tab
-f FILEDS:
#: 第#个字段,例如:3
#,#l,#]: 离散的多个字段,例如:1,3,6
#-#: 连续的多个字段,例如:1-6
混合使用~1-3,7
-c 按字符切割
--output-delimiter=STRING指定输出分隔符
例:
#df|tr -s ' ' |cut -d' ' -f5|tr -d % 快速取出df命令下的第五列磁盘空间利用率数据,最后将%删除
Use
0
0
1
0
20
1
21
1
0
#df|tr -s ' ' '%'|cut -d% -f5 快速取出df命令下的第五列磁盘空间利用率数据,且不带%
Use
0
0
1
0
20
1
21
1
0
paste 合并多个文件同行号的列到一行
格式
paste [OPTION]..[FILE].
-d分隔符 : 指定分隔符,默认用TAB
-s 所有行合成一行显示,即多行一列转换成一行多列
文本数据统计: wc
整理文本: sort
比较文件: diff和patch
wc 命令可用于统计文件的行总数、单词总数、字节总数和字符总数,可以对文件或STDIN中的数据统计
常用选项
-l 只计数行数
-W 只计数单词总数
-c 只计数字节总数
-m 只计数字符总数
-L 显示文件中最长行的长度
例:
ls /etc/ | wc -l 查看etc下有多少个文件
279
#df |tail -n $(echo `df | wc -l` -l|bc) 不显示df的第一行注释行,显示下面的9行
Filesystem 1K-blocks Used Available Use% Mounted on
devtmpfs 1969208 0 1969208 0% /dev
tmpfs 1997600 0 1997600 0% /dev/shm
tmpfs 1997600 9940 1987660 1% /run
tmpfs 1997600 0 1997600 0% /sys/fs/cgroup
/dev/sda2 104806400 20871932 83934468 20% /
/dev/sda3 52403200 398476 52004724 1% /data
/dev/sda1 999320 193956 736552 21% /boot
tmpfs 399520 24 399496 1% /run/user/0
/dev/sr0 10540998 10540998 0 100% /run/media/root/CentOS-8-5-2111-x86_64-dvd
把整理过的文本显示在STDOUT,不改变原始文件
格式:
sort [options] file(s)
常用选项
-r 执行反方向 (由上至下) 整理,一般配合-n使用
-R 随机排序
-n 执行按数字大小整理
-f 选项忽略 (fold) 字符串中的字符大小写
-u 选项 (独特,unique) 删除输出中的重复行
-t c 选项使用c做为字段界定符
-k# 选项按照使用c字符分隔的 # 列来整理能够使用多次
例:
seq 10 | sort -R 将生成的1——10的数字随机排序
9
5
7
4
8
1
6
3
10
2
uniq命令从输入中删除前后相接的重复的行
格式:
uniq [OPTION]...[FILE]..
常见选项
-c: 显示每行重复出现的次数
-d: 仅显示重复过的行
-u: 仅显示不曾重复的行
uniq常和sort 命令一起配合使用
#cut -d" " -fl access_log |sort |uniq -c|sort -nr |head -3 查看日志里访问次数最多的前三个ip地址,有排序、统计和筛选
#ss -nt|tai1 -n+2|tr -s' ' : |cut -d: -f6|sort|uniq -c|sort -nr |head -n2 查看当前主机连接次数最多的前2名,去除文件开头注释
#cat f2.txt f3.txt |sort|uniq -d 过滤出2个文件的相同行(文件本身没有重复)
1
b
c
diff命令可以比较2个文本文件的区别
patch 复制在其它文件中进行的改变 (要谨慎使用)
适用 -b 选项来自动备份改变了的文件
cmp,比较二进制文件的不同
例:
#ll /bin/ls /bin/dir
-rwxr-xr-x. 1 root root 143224 Jul 14 2021 /bin/dir
-rwxr-xr-x. 1 root root 143224 Jul 14 2021 /bin/ls
#cmp /bin/ls /bin/dir
/bin/ls /bin/dir differ: byte 793, line 1
#hexdump -s 790 -Cn 3 /bin/ls
00000316 55 00 bc |U..|
00000319
#hexdump -s 790 -Cn 3 /bin/dir
00000316 55 00 4a |U.J|
00000319
REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符
正则表达式被很多程序和开发语言所广泛支持: vim,less,grep,sed,awk,nginx,mysgl等
正则表达式分两类
正则表达式引擎:
采用不同算法,检查处理正则表达式的软件模块如: PCRE (Perl Compatible Regular Expressions)
正则表达式的元字符分类: 字符匹配、匹配次数、位置锚定、分组
帮助: man 7 regex
. 匹配任意单个字符(并非字节),所以可以是一个汉字
[] 匹配指定范围内的任意单个字符,示例: [joyce] [0-9] [a-z] [a-zA-Z]
[^] 匹配指定范围外的任意单个字符,示例: [^joyce]
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z,a-z
[:lower:] 小写字母,示例:[[:1ower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符 (空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntr1:] 不可打印的控制字符 (退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:] 十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
例:
#grep r..t /etc/passwd 显示passwd里符合r..t的行,中间可以是任意字符
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
clevis:x:976:976:Clevis Decryption Framework unprivileged user:/var/cache/clevis:/sbin/nologin
#ls /etc/|grep 'rc[.0-6]' 显示etc下所有rc后跟任意字符或0-6数字的文件
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local
#ls /etc/|grep 'rc[.0-6]\.' 显示etc下所有rc后跟任意字符或0-6数字且下一个字符是.的文件
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
用在要指定次数的字符后面,用于指定前面的字符要出现的次数
* 匹配前面的一个字符任意次,包括0次,贪婪模式: 尽可能长的匹配
.* 任意长度的任意字符,相当于任意字符串
\? 匹配其前面的字符0或1次,即:可有可无
\+ 匹配其前面的字符至少1次,即:肯定有
\{n\} 匹配前面的字符n次
\{m,n\} 匹配前面的字符至少m次,至多n次
\{,n\} 匹配前面的字符至多n次
\{n,\} 匹配前面的字符至少n次
例:
#echo helo|grep 'hel*o' 输出任意个l的字符串
helo
]#echo helllllllllllllo|grep 'hel*o' 输出人一个l的字符串
helllllllllllllo
#echo hello|grep 'hel\+o' 输出至少包含1个l的字符串
hello
位置锚定可以用于定位出现的位置
^ 行首错定,用于模式的最左侧
$ 行尾错定,用于模式的最右侧
^PATTERN$ 用于模式匹配整行
^$ 空行
^[[:space:]]*$ 空白行
\< 或 \b 词首错定,用于单词模式的左侧
\> 或 \b 词尾错定,用于单词模式的右侧
\<PATTERN\> 匹配整个单词
例:
#grep ^.[joyce] /etc/passwd 显示passwd中以任意字符开头且第二个字符是joyce任意一个字符的行
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin
#grep -v '^$' /etc/profile|grep -v ^# 过滤profile中以#开头的注释行和空行
#df |grep '^/dev/sd'|grep -o ' *[1-9]\?[0-9]%' 显示df中dev/sda磁盘空间利用率那一列的数据(区间0-99)
20%
1%
21%
分组: 0 将多个字符捆绑在一起,当作一个整体处理,如: (root)+
后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为:\1,2,3;\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
例:
#echo abcabcabc |grep 'abc\{3\}' 直接这样写匹配的是abccc
#echo abcabcabc |grep '\(abc\)\{3\}' 将abc加小括号分组成一个整体,就可以匹配abc
abcabcabc
注意:后向引用中引用前面的分组括号中的模式所匹配字符,而非模式本身
或者:\
例:在vim编辑器的命令模式下
:%s$^#\(.*\)$\1$ 将每行以#开头的其后的内容全部分组并重新赋值给这一行,即删除所有行首的#号
:%s$^#$$ 将每行以#开头的#全部替换为空,即删除所有行首的#号
:%s$^UUID$#UUID$ 或 :%s$^\(UUID)\$#\1$ 将所有UUID开头的行前加上#号
或者:
\|
例:
#grep -v '^#\|^$' /etc/profile 以 或者 的方式过滤profile中以#开头的注释行和空行
#grep -v '^\(#\|$\)' /etc/profile 以 分组和或者 的方式 过滤profile中以#开头的注释行和空行
#grep -v "^[^#]" /etc/profile 先排除所有以#开头的行,再输出至少包含1个字符(即非空行,[])
基本上是删除\,前面加-E选项或者使用egrep即可
. 匹配任意单个字符(并非字节),所以可以是一个汉字
[] 匹配指定范围内的任意单个字符,示例: [joyce] [0-9] [a-z] [a-zA-Z]
[^] 匹配指定范围外的任意单个字符,示例: [^joyce]
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z,a-z
[:lower:] 小写字母,示例:[[:1ower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符 (空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntr1:] 不可打印的控制字符 (退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:] 十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
* 匹配前面的一个字符任意次,包括0次,贪婪模式: 尽可能长的匹配
? 匹配其前面的字符0或1次,即:可有可无
+ 匹配其前面的字符至少1次,即:肯定有
{n} 匹配前面的字符n次
{m,n} 匹配前面的字符至少m次,至多n次
^ 行首错定,用于模式的最左侧
$ 行尾错定,用于模式的最右侧
\< 或 \b 词首错定,用于单词模式的左侧
\> 或 \b 词尾错定,用于单词模式的右侧
() 分组
后向引用:\1,\2,...
| 或者
a|b #a或b
c|cat #C或cat
(c|c)at #Cat或cat
grep: Global search REgular expression and Print out the line
格式:
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 递归目录,处理软链接
例:
#grep -e root -e bash /etc/passwd 查询passwd下包含root或bash的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
joyce:x:1000:1000:Joyce:/home/joyce:/bin/bash
nana:x:1001:1001::/home/nana:/bin/bash
#grep root /etc/passwd|grep bash 查询passwd下同时包含root和bash的行
root:x:0:0:root:/root:/bin/bash
##3过滤出f2和f3两个文件的相同行(文件本身没有重复)
#cat f2.txt
a
b
1
c
#cat f3.txt
b
e
f
c
1
2
#cat f2.txt f3.txt
a
b
1
c
b
e
f
c
1
2
#grep -f f2.txt f3.txt
b
c
1
// 4输出df下的包含ip地址所在行的第一个地址
#ifconfig ens160 |egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'|head -1
10.0.0.201
#ifconfig ens160 |egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}'|head -1
10.0.0.201
注意:地址数字后的.前要加\转义,否则代表任意字符,而不是地址中的.
#cat /data/nianling.txt 输出nianling.txt文件中几个人年龄之和
a=20
b=18
c=22
#cat /data/nianling.txt |cut -d= -f2|tr '\n' '+'|grep -Eo ".*[0-9]+"|bc
60
#cat /data/nianling.txt |cut -d= -f2|tr '\n' '+'|grep -Eo ".*[0-9]"|bc
60
#cat /data/nianling.txt |grep -Eo "[0-9]+"|tr '\n' '+'|grep -Eo ".*[0-9]"|bc
60
#grep -Eo "[0-9]+" nianling.txt|tr '\n' '+'|grep -Eo ".*[0-9]"|bc
60
sed 即 Stream EDitor,和 vi 不同,sed是行编辑器
Sed是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行,再输出一行,直到最后一行.每当处理一行时,把当前处理的行存储在临时缓冲区中,称为模式空间(Pattern Space) ,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。一次处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象。
如果使用vi命令打开几十M上百M的文件,明显会出现有卡顿的现象,这是因为vi命令打开文件是一次性将文件加载到内存,然后再打开。
Sed就避免了这种情况,一行一行的处理,打开速度非常快,执行速度也很快
参考网站: http://www.gnu.org/software/sed/manual/sed.html
修改是的模式空间,即内存空间,并非文件
格式
sed [option]... 'script;script;...' inputfile...
常用选项
-n 不输出模式空间内容到屏幕,即关闭自动打印
-e 多点编辑
-f /PATH/SCRIPT_FILE 从指定文件中读取编辑脚本
-r,-E 使用扩展正则表达式
-i.bak 备份文件并原处编辑
script格式
'地址命令'
地址格式:
1. 不给地址 对全文进行处理
2. 单地址:
#:指定的行,$:最后一行
/pattern/:被此处模式所能够匹配到的每一行
3. 地址范围:
#,# 第几行到第几行
#,+# 第几行到后面几行
/pat1/,/pat2/ 从哪个模式到哪个模式
#,/pat/ 从第几行到哪个模式
4. 步进:~
1~2 奇数行
2~2 偶数行
例:
[root@CentOS8 data]#sed -n '/^[^#]/p' /etc/fstab 打印/etc/fstab中非#开头的行
UUID=f2c173be-7848-43e9-9d0b-da0f1841f93f / xfs defaults 0 0
UUID=54ead45a-7577-4b54-9de2-501aef04207a /boot ext4 defaults 1 2
UUID=499afcaa-85a4-4b87-9223-20497b0bcf94 /data xfs defaults 0 0
[root@CentOS8 data]#sed -n '/root/p' passwd 范围查找包含root的
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@CentOS8 data]#nl passwd | sed -n '3,6p' 从3到6行
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
[root@CentOS8 data]#nl passwd | sed -n '3,+1p' 从3到3+1=4行
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
[root@CentOS8 data]#sed -n '/^d/,/^s/p' passwd 找到d开头到s开头的行
daemon:x:2:2:daemon:/sbin:/sbin/nologin d开头
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync s开头
dbus:x:81:81:System message bus:/:/sbin/nologin d开头
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin s开头
dnsmasq:x:983:983:Dnsmasq DHCP and DNS server:/var/lib/dnsmasq:/sbin/nologin d开头
radvd:x:75:75:radvd user:/:/sbin/nologin
sssd:x:982:982:User for sssd:/:/sbin/nologin s开头
[root@CentOS8 data]#nl passwd | sed -n '1~2p' 将passwd文件从1行开始2为间隔打印,即1、3、5、7....
1 root:x:0:0:root:/root:/bin/bash
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
11 games:x:12:100:games:/usr/games:/sbin/nologin
13 nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologi
命令:
p 打印当前模式空间内容,追加到默认输出之后,即打印显示(sed命令默认操作是自动打印,再p会打印2次)
Ip 忽略大小写输出
d 删除模式空间匹配的行,并立即启用下一轮循环
a [\\]text 在指定行后面追加文本,支持使用\n实现多行追加
i [\\]text 在行前面插入文本
c [\\]text 替换行为单行或多行文本
w /path/fiTe 保存模式匹配的行至指定文件
r /path/file 读取指定文件的文本至模式空间中匹配到的行后
= 为模式空间中的行打印行号
! 模式空间中匹配行取反处理
s/pattern/string/修饰符 查找替换,支持使用其它分隔符,可以是其它形式: s@@@,s###
替换修饰符:
g 行内全局替换,而不是只替换第一个
p 显示替换成功的行
w /PATH/FILE 将替换成功的行保存至文件中
I,i 忽略大小写
例:
[root@CentOS8 data]#sed -n '/root/!p' passwd 打印不包含root的行
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
[root@CentOS8 data]#seq 10 | sed '5,8a\ abc \n123' 在第5行后至第8行追加\ abc(加\转义 空格),然后\n换行加123
1
2
3
4
5
abc
123
6
abc
123
7
abc
123
8
abc
123
9
10
[root@CentOS8 data]#seq 10 | sed '5,8c\ abc \n123' 将第五行到第八行换成 abc\n123
1
2
3
4
abc
123
9
10
[root@CentOS8 data]#seq 10 | sed -e '5a\abc' -e '5i\123' 在第五行前加123,后加abc
1
2
3
4
123
5
abc
6
7
8
9
10
[root@CentOS8 data]#seq 10 | sed -n '1,4w /data/seq.log' 将seq 10生成的1到4行写入到seq.log文件中
[root@CentOS8 data]#cat seq.log
1
2
3
4
[root@CentOS8 data]#seq 10 | sed '2,5r /etc/issue' 将seq 10生成的2到5行后面都加上issue文件的内容
1
2
Time at \t
Terminal on \l
\S
Kernel \r on an \m
3
Time at \t
Terminal on \l
\S
Kernel \r on an \m
4
Time at \t
Terminal on \l
\S
Kernel \r on an \m
5
Time at \t
Terminal on \l
\S
Kernel \r on an \m
6
7
8
9
10
[root@centos8_2 ~]#sed -Ei.bak 's/^(SELINUX=).*/\1enforcing/' /etc/selinux/config
将config文件里SELINUX=后面的字符替换为enforcing,()分组,后使用\1替代
将grub文件里以GRUB_CMDLINE_LINUX=开头的行其中以"为结尾的前面加上net.ifnames=0,即修改网卡配置
[root@centos8_2 ~]#sed -Ei.bak '/^GRUB_CMDLINE_LINUX=/s/(.*)"$/\1 net.ifnames=0"/' /etc/default/grub
[root@centos8_2 ~]#sed -Ei.bak 's/quiet/quiet net.ifnames=0/' /etc/default/grub
[root@centos8_2 ~]#sed -Ei.bak '/^GRUB_CMDLINE_LINUX=/s/(.*)(")$/\1 net.ifnames=0\2/' /etc/default/grub
例:修改网卡名称
[root@centos8 ~]#sed -ri '/AGRUBCMDLINE_LINUX=/s@"$@ net.ifnames=0"@' /etc/default/grub
#centos7,8:
[root@centos8 ~]#grub2-mkconfig -o /boot/grub2/grub.cfg
#ubuntu:
[root@ubuntu ~]#grub-mkconfig -o /boot/grub/grub.cfg
范例:取基名和目录名
echo "/etc/sysconfig/network-scripts/" |sed -r 's#(^/.*/)([^/]+/?)#\2#' 取基名
echo "/etc/sysconfig/network-scripts/" |sed -r 's#(^/.*/)([^/]+/?)#\1#' 取目录
#取目录名
[root@centos8 ~]#echo /etc/sysconfig/ |sed -rn 's#(.*)/([^/]+)/?#\1#p'
/etc
#取基名
[root@centos8 ~]#echo /etc/sysconfig/ |sed -rn 's#(.*)/([^/]+)/?#\2#p'
sysconfig
同一个文件:
[root@centos8 ~]#sed -ri.bak '/^#/!s/^/#/' /etc/fstab 在非#开头的行首加上#
[root@centos8 ~]#sed -ri.bak '/^#/!s/$/#/' /etc/fstab 在非#开头的行尾加上#
[root@CentOS8 ~]#sed -r '/default/s/(defaults)/#\1/' /etc/fstab 在defaults的前面加上#
[root@CentOS8 data]#sed -r "/default/s/(defaults)/$PS1\1/" /etc/fstab 在default前面加上变量$PS1,要使变量显示,使用""双引号
[root@CentOS8 data]#sed -r '/default/s/(defaults)/'''$PS1'''\1/' /etc/fstab 或使用单引号'',但在变量前后各加三个',亲测失败
sed 中除了模式空间,还另外还支持保持空间 (Hold space),利用此空间,可以将模式空间中的数据,临时保存到保持空间,从而后续接着处理,实现更为强大的功能。
常见的高级命令
P 打印模式空间开端至\n内容,并追加到默认输出之前
h 把模式空间中的内容覆盖至保持空间中
H 把模式空间中的内容追加至保持空间中
g 从保持空间取出数据覆盖至模式空间
G 从保持空间取出内容追加至模式空间
x 把模式空间中的内容与保持空间中的内容进行互换
n 读取匹配到的行的下一行覆盖至模式空间
N 读取匹配到的行的下一行追加至模式空间
d 删除模式空间中的行
D 如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,并不会读取新的输入行,而使用合成的模式空间重新启动循环。如果模式空间不包含换行符,则会像发出d命令那样启动正常的新循环
范例:
sed -n 'n;p' FILE
sed '1!G;h;$!d' FILE
sed 'N;D' FILE
seq 10 | sed '3h;9G;9!d'
sed '$!N;$!D' FILE
sed '$!d' FILE
sed 'G' FILE
sed 'g' FILE
sed '/^$/d;G' FILE
sed 'n;d' FILE
sed -n '1!G;h;$p' FILE
例:
[root@CentOS8 data]#seq 4 | sed -n 'n;p' 打印偶数行
2
4
[root@CentOS8 data]#seq 4 | sed '1!G;h;$!d' 倒序显示
4
3
2
1
[root@CentOS8 data]#seq 4 | sed 'N;D' 打印最后一行
4
**awk: Aho, Weinberger,Kernighan,报告生成器,**格式化文本输出,GNU/Linux发布的AWK目前由自由软件基金会 (FSF) 进行开发和维护,通常也称它为 GNU AWK
有多种版本:
gawk: 模式扫描和处理语言,可以实现下面功能
格式
awk [options] 'program' var=value file..
awk [options] -f programfile var=value file...
说明:
program通常是被放在单引号中,并可以由三种部分组成
常见选项:
Program格式:
pattern{action statements;..}
pattern: 决定动作语句何时触发及触发事件,比如: BEGIN(整个文件处理前先进行),END(整个文件处理后再执行),正则表达式等
action statements:对数据进行处理,放在{}内指明,常见:print,printf
awk 工作过程
BEGIN语句块在awk开婚从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
patern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print},即打印每一个读取到的行,awk读取的每一行都会执行该语句块
分割符、域和记录
常用的action分类
awk控制语句
例:
[root@CentOS8 test]#cat awk_1-scripts
{print script"\t"$1"\t"$2}
[root@CentOS8 test]#awk -F: -f awk_1-scripts script="awk" /etc/passwd|head -5
awk root x
awk bin x
awk daemon x
awk adm x
awk lp x
格式:
print item1, item2,
说明:
例:
[root@CentOS8 ~]#awk '{print "ok"}' #固定字符串要加双引号
hello
ok
ohno
ok
yes
ok
z
ok
[root@CentOS8 ~]#seq 5 | awk '{print "ok"}'
ok
ok
ok
ok
ok
[root@CentOS8 ~]#awk '{print 2*3}'
das
6
czxc
6
sada
6
[root@CentOS8 ~]#seq 3|awk '{print 2*3}'
6
6
6
[root@CentOS8 ~]#awk -F: '{print "okk"}' /etc/issue #issue有几行,打印几次okkk
okk
okk
okk
okk
okk
okk
okk
[root@CentOS8 ~]#awk '{print "okk"}' /etc/issue
okk
okk
okk
okk
okk
okk
okk
[root@CentOS8 ~]#awk '{print}' /etc/issue
Time at \t
Terminal on \l
\S
Kernel \r on an \m
[root@CentOS8 ~]#awk -F: '{print}' /etc/issue
Time at \t
Terminal on \l
\S
Kernel \r on an \m
[root@CentOS8 ~]#awk -F: '{print $0}' /etc/issue
Time at \t
Terminal on \l
\S
Kernel \r on an \m
[root@CentOS8 ~]#awk -F: '{print $1}' /etc/passwd | head -5 #以:为分隔符,打印passwd文件的第一列
root
bin
daemon
adm
lp
[root@CentOS8 ~]#awk -F: '{print $1":"$3}' /etc/passwd | head -5
root:0
bin:1
daemon:2
adm:3
lp:4
[root@CentOS8 ~]#awk -F: '{print $1,$3}' /etc/passwd | head -5
root 0
bin 1
daemon 2
adm 3
lp 4
[root@CentOS8 ~]#awk -F: '{print $1"\t"$3}' /etc/passwd | head -5
root 0
bin 1
daemon 2
adm 3
lp 4
[root@CentOS8 test]#awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd |head -5
root male #第一行age没有值,第二行开始赋值才有
bin male 18
daemon male 18
adm male 18
lp male 18
例:取出df下文件系统和分区利用率
[root@CentOS8 ~]#df | awk '{print $1"\t"$5}' #单awk
Filesystem Use%
devtmpfs 0%
tmpfs 0%
tmpfs 1%
tmpfs 0%
/dev/sda2 40%
/dev/sda3 1%
/dev/sda1 21%
tmpfs 1%
tmpfs 0%
[root@CentOS8 ~]#df | awk '{print $1"\t"$5}'|awk -F% '{print $1}' #双awk
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 1
tmpfs 0
/dev/sda2 40
/dev/sda3 1
/dev/sda1 21
tmpfs 1
tmpfs 0
[root@CentOS8 ~]#df | awk '{print $1"\t"$5}'| tr -d '%' #awk+tr
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 1
tmpfs 0
/dev/sda2 40
/dev/sda3 1
/dev/sda1 21
tmpfs 1
tmpfs 0
[root@CentOS8 ~]#df | awk -F' +|%' '{print $1,$5}' #带两个分隔符的awk,扩展的正则表达式
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 1
tmpfs 0
/dev/sda2 40
/dev/sda3 1
/dev/sda1 21
tmpfs 1
tmpfs 0
[root@CentOS8 ~]#df | awk -F'[[:space:]]+|%' '{print $1,$5}' #带两个分隔符的awk
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 1
tmpfs 0
/dev/sda2 40
/dev/sda3 1
/dev/sda1 21
tmpfs 1
tmpfs 0
#取出特定文件系统,grep实现
[root@CentOS8 ~]#df |grep '^/dev/sd' | awk -F'[[:space:]]+|%' '{print $1,$5}'
/dev/sda2 40
/dev/sda3 1
/dev/sda1 21
#取出特定文件系统,正则表达式实现
[root@CentOS8 ~]#df | awk -F'[[:space:]]+|%' '/^\/dev\/sd/{print $1,$5}' /dev/sda2 40
/dev/sda3 1
/dev/sda1 21
例:取出ifconfig里的ip地址
[root@CentOS8 ~]#ifconfig eth0 | awk -F' +' '/netmask/{print $3}'
10.0.0.201
[root@CentOS8 ~]#ifconfig eth0 | awk '/netmask/{print $2}'
10.0.0.201
[root@CentOS8 ~]#ifconfig eth0 | sed -rn '2s/^[^0-9]+([0-9.]+) .*$/\1/p' #sed实现,C678均可使用
10.0.0.201
[root@CentOS8 test]#ifconfig eth0 | awk -F' +' 'NR==2{print $3}'
10.0.0.201 #NR
范例: 取出日志里网站访问量最大的前3个IP
[root@VM_0_10_centos logs]# awk '{print $1}' nginx.access.log-20200428| sort| uniq -c|sort -nr|head -3
5498 122.51.38.20
2161 117.157.173.214
953 211.159.177.120
[root@centos8 ~]#awk '{print $1}' access_log| sort| uniq -c|sort -nr|head -3
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
2613 172.20.112.14
面试题: 文件hosts.log 如下格式,请提取"joyce.com"前面的主机名部分并追加到该文件后方
[root@CentOS8 ~]#cat hosts.log
1 www.joyce.com
2 blog.joyce.com
3 study.joyce.com
4 linux.joyce.com
5 C++.joyce.com
[root@CentOS8 ~]#awk -F'[ .]' '{print $2}' hosts.log
www
blog
study
linux
C++
[root@CentOS8 ~]#awk -F'[ .]' '{print $2}' hosts.log >> hosts.log
[root@CentOS8 ~]#cat hosts.log
1 www.joyce.com
2 blog.joyce.com
3 study.joyce.com
4 linux.joyce.com
5 C++.joyce.com
www
blog
study
linux
C++
printf 可以实现格式化输出
格式:
printf “FORMAT”,item1, item2,...
说明:
格式符: 与item一一对应
修饰符
#[.#] 第一个数字控制显示的宽度: 第二个#表示小数点后精度,如: %3.1f
- 左对齐(默认右对齐) 如: %-15s
+ 显示数值的正负符号 如: %+d
例:
[root@CentOS8 test]#awk -F: '{printf "%s",$1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodydbussystemd-coredumpsystemd-resolvetsspolkitdgeocluertkitpipewirepulseqemuusbmuxdunboundglusterrpcavahichronysaslauthlibstoragemgmtdnsmasqradvdsssdcockpit-wscockpit-wsinstancecolordrpcusersetroubleshootflatpakgdmclevisgnome-initial-setuptcpdumpsshdjoycepostfixnanamysqljoyceeapacheTomAlicepcp
[root@CentOS8 test]#awk -F: '{printf "%s\n",$1}' /etc/passwd | head -5
root
bin
daemon
adm
lp
[root@CentOS8 test]#awk -F: '{printf "%10s\n",$1}' /etc/passwd | head -5
root
bin
daemon
adm
lp
[root@CentOS8 test]#awk -F: '{printf "%-10s\n",$1}' /etc/passwd | head -5
root
bin
daemon
adm
lp
[root@CentOS8 test]#awk -F: '{printf "%-10s %10d\n",$1,$3}' /etc/passwd | head -5
root 0 #注意,要让$1/$3在同一行,前面不加\n,后面加
bin 1 #-负数左对齐
daemon 2
adm 3
lp 4
[root@CentOS8 test]#awk -F: '{printf "%10s %10d\n",$1,$3}' /etc/passwd | head -5
root 0
bin 1
daemon 2
adm 3
lp 4
[root@CentOS8 test]#awk -F: 'BEGIN{print "------------------------"}{printf "%-10s | %10d\n------------------------\n",$1,$3}' /etc/passwd | head -10
------------------------
root | 0
------------------------
bin | 1
------------------------
daemon | 2
------------------------
adm | 3
------------------------
lp | 4
[root@CentOS8 test]#awk -F: '{printf "%-10s | %10d\n------------------------\n",$1,$3}' /etc/passwd | head -10 root | 0
------------------------
bin | 1
------------------------
daemon | 2
------------------------
adm | 3
------------------------
lp | 4
------------------------
[root@CentOS8 test]#awk -F: '{printf "UserName: %s\n",$1}' /etc/passwd |head -5
UserName: root
UserName: bin
UserName: daemon
UserName: adm
UserName: lp
[root@CentOS8 test]#awk -F: '{printf "UserName: %s %3.3f\n",$1,$3}' /etc/passwd |head -5
UserName: root 0.000
UserName: bin 1.000
UserName: daemon 2.000
UserName: adm 3.000
UserName: lp 4.000
[root@CentOS8 test]#awk -F: '{printf "UserName: %10s %10.3f\n",$1,$3}' /etc/passwd |head -5
UserName: root 0.000
UserName: bin 1.000
UserName: daemon 2.000
UserName: adm 3.000
UserName: lp 4.000
awk中的变量分为:内置和自定义变量
常见的内置变量
输入字段分隔符,默认为空白字符,功能相当于 -F
范例:
[root@CentOS8 ~]#awk -v FS=":" '{print $1}' /etc/passwd | head -5
root
bin
daemon
adm
lp
[root@CentOS8 ~]#awk -v FS=":" '{print $1FS$3}' /etc/passwd | head -5
root:0
bin:1
daemon:2
adm:3
lp:4
[root@CentOS8 ~]#S=:; awk -v FS=$S '{print $1FS$3}' /etc/passwd | head -5
root:0
bin:1
daemon:2
adm:3
lp:4
[root@CentOS8 ~]#S=:; awk -F$S '{print $1,$3}' /etc/passwd | head -5
root 0
bin 1
daemon 2
adm 3
lp 4
#同时存在两个类型的分隔符时,后面的生效
[root@CentOS8 ~]#awk -v FS=":" -F="-" '{print $1FS$3}' /etc/passwd | head -5
root:x:0:0:root:/root:/bin/bash=-
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=-
[root@CentOS8 ~]#awk -F="-" -v FS=":" '{print $1FS$3}' /etc/passwd | head -5
root:0
bin:1
daemon:2
adm:3
lp:4
输出字段分隔符,默认为空白字符**
范例:
[root@CentOS8 ~]#awk -F: '{print $1,$3}' /etc/passwd | head -5
root 0
bin 1
daemon 2
adm 3
lp 4
[root@CentOS8 ~]#awk -F: -v OFS='--' '{print $1,$3}' /etc/passwd | head -5
root--0
bin--1
daemon--2
adm--3
lp--4
输入记录分隔符,指定输入时的换行符
范例:
[root@CentOS8 test]#cat test1.txt
a,b,c;12
33,44,55;AA
CC
[root@CentOS8 test]#awk -F"," '{print $1,$3}' test1.txt
a c;12
33 55;AA
CC
[root@CentOS8 test]#awk -F"," -v RS=";" '{print $1,$3}' test1.txt
a c
12
33 55
AA
CC
[root@CentOS8 test]#awk -v FS="," -v RS=";" '{print $1,$3}' test1.txt
a c
12
33 55
AA
CC
输出记录分隔符,输出时用指定符号代替换行符**
[root@CentOS8 test]#awk -v FS="," -v RS=";" -v ORS="|" '{print $1,$3}' test1.txt
a c|12 #因为本身有换行,所以这里会换行
33 55|AA
CC
|
字段数量
[root@CentOS8 test]#]#awk -v FS="," -v RS=";" '{print NF}' test1.txt
3
3
1
[root@CentOS8 test]#awk -F: '{print NF}' /etc/passwd | head -4
7
7
7
7
[root@CentOS8 test]#awk -F: '{print $NF}' /etc/passwd | head -4
/bin/bash #取倒数第一列(即最后一列)
/sbin/nologin
/sbin/nologin
/sbin/nologin
[root@CentOS8 test]#awk -F: '{print $1,$NF}' /etc/passwd | head -4
root /bin/bash #取第一列和倒数第一列(即最后一列)
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
[root@CentOS8 test]#awk -F: '{print $1"\t"$NF}' /etc/passwd | head -4
root /bin/bash #取第一列和倒数第一列(即最后一列)
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
[root@CentOS8 test]#awk -F: '{print $(NF-1)}' /etc/passwd | head -4
/root #取倒数第二列
/bin
/sbin
/var/adm
例:提取/misc/cd/BaseOS/Packages/*.rpm的架构后缀
[root@CentOS8 test]#ls /misc/cd/BaseOS/Packages/*.rpm | head -5
/misc/cd/BaseOS/Packages/aajohan-comfortaa-fonts-3.001-2.el8.noarch.rpm
/misc/cd/BaseOS/Packages/accel-config-3.1-1.el8.i686.rpm
/misc/cd/BaseOS/Packages/accel-config-3.1-1.el8.x86_64.rpm
/misc/cd/BaseOS/Packages/accel-config-libs-3.1-1.el8.i686.rpm
/misc/cd/BaseOS/Packages/accel-config-libs-3.1-1.el8.x86_64.rpm
[root@CentOS8 test]#ls /misc/cd/BaseOS/Packages/*.rpm | awk -F"." '{print $(NF-1)}'|sort | uniq -c
403 i686
224 noarch
1082 x86_64
例:取出ss -nt 下访问数最多的ip
[root@CentOS8 ~]#ss -nt
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
ESTAB 0 0 10.0.0.201:22 10.0.0.1:58285
ESTAB 0 48 10.0.0.201:22 10.0.0.1:61841
ESTAB 0 0 10.0.0.201:53854 151.101.1.91:443
ESTAB 0 0 10.0.0.201:22 10.0.0.1:61842
[root@CentOS8 ~]#ss -nt | awk -F" +|:" '{print $(NF-2)}'
Address #+号代表一个以上
10.0.0.1
10.0.0.1
151.101.1.91
10.0.0.1
[root@CentOS8 ~]#ss -nt | awk -F" +|:" '{print $(NF-2)}'| sort| uniq -c
3 10.0.0.1
1 151.101.1.91
1 Address
[root@CentOS8 ~]#ss -nt | awk -F" +|:" '/^ESTAB/{print $(NF-2)}'| sort| uniq -c|sort -nr|head -2
3 10.0.0.1 #仅包含ESTAB开头的
1 151.101.1.91
例:脚本:将ip地址访问次数最多的2个地址加入到防火墙
[root@CentOS8 test]#cat through_into_firewall.sh
#!/bin/bash
IPLIST= `ss -nt | awk -F" +|:" '/^ESTAB/{print $(NF-2)}'| sort| uniq -c|sort -nr|head -2|awk '{print $2}'`
for ip in $IPLIST ;do
iptables -A INPUT -s $ip -j REJECT
done
例:创建计划任务,每10min将ip并发数大于100的ip地址加入黑名单
[root@CentOS8 ~]#cat /test/deny_dos.sh
LINK=100
while true;do
ss -nt I awk -F[[:space:]]+:" '/AESTAB/[print S(NF-2)]'sort luniq -clwhile read
count ip;do
if [ $count -gt $LINK ];then
iptables -A INPUT -s $ip -j REJECT
fi
done
done
[root@CentOS8 test]#chmod +x /test/deny_dos.sh
[root@CentOS8 test]#crontab -e
*/10 * * * * * /test/deny_dos.sh
记录的编号,可以反映行数
例:
[root@CentOS8 test]#seq 5 | awk '{print NR}'
1
2
3
4
5
[root@CentOS8 test]#awk '{print NR}' /etc/passwd |head -7
1
2
3
4
5
6
7
[root@CentOS8 test]#awk 'NR==3' /etc/passwd #显示第二行的信息
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@CentOS8 test]#ifconfig eth0 | awk -F' +' 'NR==2{print $3}' #显示第二行
10.0.0.201
[root@CentOS8 test]#cat test1.txt
a,b,c;12
33,44,55;AA
CC
[root@CentOS8 test]#awk -v RS=";" '{print NR}' test1.txt
1
2
3
[root@CentOS8 test]#awk -v RS=";" '{print NR,$0}' test1.txt
1 a,b,c
2 12
33,44,55
3 AA
CC
#多文件会合并再一次
[root@CentOS8 test]#awk '{print NR,$0}' /etc/issue /etc/centos-release
1 Time at \t
2 Terminal on \l
3
4
5 \S
6 Kernel \r on an \m
7
8 CentOS Linux release 8.5.2111
各文件分别记录
例:
[root@CentOS8 test]#awk '{print NR,$0}' /etc/issue /etc/centos-release
1 Time at \t #NR合并再一次
2 Terminal on \l
3
4
5 \S
6 Kernel \r on an \m
7
8 CentOS Linux release 8.5.2111
[root@CentOS8 test]#awk '{print FNR,$0}' /etc/issue /etc/centos-release
1 Time at \t #FNR分别记录编号
2 Terminal on \l
3
4
5 \S
6 Kernel \r on an \m
7
1 CentOS Linux release 8.5.2111
显示当前文件名
[root@CentOS8 test]#awk '{print FNR,FILENAME,$0}' /etc/issue /etc/centos-release
1 /etc/issue Time at \t
2 /etc/issue Terminal on \l
3 /etc/issue
4 /etc/issue
5 /etc/issue \S
6 /etc/issue Kernel \r on an \m
7 /etc/issue
1 /etc/centos-release CentOS Linux release 8.5.2111
命令行参数的个数
[root@CentOS8 test]#awk '{print ARGC}' /etc/issue /etc/centos-release
3
3
3
3
3
3
3
3
[root@CentOS8 test]#awk -F: '{print ARGC}' /etc/issue /etc/centos-release
3
3
3
3
3
3
3
3
**数组,保存命令行所给定的各参数,第一个参数ARGV[0],第二个ARGV[1],… **
[root@CentOS8 test]#awk -F: '{print ARGV[0],ARGV[1],ARGV[2]}' /etc/issue /etc/centos-release
awk /etc/issue /etc/centos-release
awk /etc/issue /etc/centos-release
awk /etc/issue /etc/centos-release
awk /etc/issue /etc/centos-release
awk /etc/issue /etc/centos-release
awk /etc/issue /etc/centos-release
awk /etc/issue /etc/centos-release
awk /etc/issue /etc/centos-release
x+y,x-y,x*y,x/y,x^y, x%y
-x:转换为负数
+x:将字符串转换为数值
字符串操作符:没有符号的操作符,字符串连接
=,+=,-=,*=, /=,%=,^=,++,--
例:
[root@CentOS8 test]#awk 'BEGIN{print 3*4}'
12
[root@CentOS8 test]#awk 'BEGIN{i=0;print ++i,i}'
1 1
[root@CentOS8 test]#awk 'BEGIN{i=0;print i++,i}'
0 1
[root@CentOS8 test]#awk -v n=0 '!n++' /etc/passwd #等价于下一个
root:x:0:0:root:/root:/bin/bash #!n++满足不为0才执行后面print
[root@CentOS8 test]#awk -v n=0 '!n++{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@CentOS8 test]#awk -v n=0 '!n++{print n}' /etc/passwd
1
[root@CentOS8 test]#awk -v n=0 '!++n{print n}' /etc/passwd
[root@CentOS8 test]#awk -v n=-1 '!++n{print n}' /etc/passwd
0
[root@CentOS8 test]#awk -v n=1 '!++n{print n}' /etc/passwd
==,!=,>,>=,<,<=
例:
[root@CentOS8 test]#awk 'NR==2' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
[root@CentOS8 test]#awk -F: '$3>=1000' /etc/passwd
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
joyce:x:1000:1000:Joyce:/home/joyce:/bin/bash
nana:x:1001:1001::/home/nana:/bin/bash
joycee:x:1002:1002::/home/joycee:/bin/bash
Tom:x:1003:1003::/home/Tom:/bin/bash
Alice:x:1004:1004::/home/Alice:/bin/bash
例:取奇偶数行
[root@CentOS8 test]#awk 'NR%2==0' /etc/passwd |head -5
bin:x:1:1:bin:/bin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
halt:x:7:0:halt:/sbin:/sbin/halt
operator:x:11:0:operator:/root:/sbin/nologin
[root@CentOS8 test]#awk 'NR%2==1' /etc/passwd |head -5
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
~ 左边是否和右边匹配,包含关系
!~ 是否不匹配
例:
[root@CentOS8 test]#awk -F: '$0 ~ /root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@CentOS8 test]#awk -F: '$0 !~ /root/' /etc/passwd |head -5
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
sync:x:5:0:sync:/sbin:/bin/sync
与&&,或||,非!
范例:
[root@CentOS8 test]#awk -v i=3 'BEGIN{print !i}'
0
[root@CentOS8 test]#awk -v i=-3 'BEGIN{print !i}'
0
[root@CentOS8 test]#awk -v i=0 'BEGIN{print !i}'
1
[root@CentOS8 test]#awk -v i=asbda 'BEGIN{print !i}'
0
[root@CentOS8 test]#awk -v i='' 'BEGIN{print !i}'
1
[root@CentOS8 test]#awk -v i="" 'BEGIN{print !i}'
1
[root@CentOS8 test]#awk -F: '$3>800 && $3<=1000' /etc/passwd|head -5
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin
polkitd:x:998:996:User for polkitd:/:/sbin/nologin
geoclue:x:997:995:User for geoclue:/var/lib/geoclue:/sbin/nologin
pipewire:x:996:992:PipeWire System Daemon:/var/run/pipewire:/sbin/nologin
unbound:x:995:989:Unbound DNS resolver:/etc/unbound:/sbin/nologin
[root@CentOS8 test]#awk -F: '$3>800 && $3<=1000 {print $1,$3}' /etc/passwd|head -5
systemd-coredump 999
polkitd 998
geoclue 997
pipewire 996
unbound 995
[root@CentOS8 test]#awk -F: '$3==0 || $3>=1000 {print $1,$3}' /etc/passwd|head -5
root 0
nobody 65534
joyce 1000
nana 1001
joycee 1002
[root@CentOS8 test]#awk -F: '!($3>=1000) {print $1,$3}' /etc/passwd|head -5
root 0
bin 1
daemon 2
adm 3
lp 4
[root@CentOS8 test]#awk -F: '! $3>=1000 {print $1,$3}' /etc/passwd|head -5
[root@CentOS8 test]#awk -F: '! $3==0 {print $1,$3}' /etc/passwd|head -5
bin 1
daemon 2
adm 3
lp 4
sync 5
[root@CentOS8 test]#awk -F: '!($3==0) {print $1,$3}' /etc/passwd|head -5
bin 1
daemon 2
adm 3
lp 4
sync 5
例:取反的高级用法
[root@CentOS8 test]#seq 5|awk 'i==0'
1
2
3
4
5
[root@CentOS8 test]#seq 5|awk 'i=0'
[root@CentOS8 test]#seq 5|awk 'i=1'
1
2
3
4
5
[root@CentOS8 test]#seq 5|awk 'i=!i'
1
3
5
[root@CentOS8 test]#seq 5|awk '!(i=!i)'
2
4
[root@CentOS8 test]#seq 5|awk -v i=1 'i=!i'
2
4
[root@CentOS8 test]#seq 5|awk '{i=!i;print i}'
1
0
1
0
1
selector?if-true-expression:if-false-expression
例:
[root@CentOS8 test]#awk -F: '{$3>=1000?usertype="Common User":usertype="SysUser";printf "%-10s:%10s\n",$1,usertype}' /etc/passwd|tail -5 #大于1000Common,小于Sys
joycee :Common User
apache : SysUser
Tom :Common User
Alice :Common User
pcp : SysUser
PATTERN:根据pattern条件,过滤匹配的行,再做处理
1 如果未指定: 空模式,匹配每一行
范例:
[root@CentOS8 test]#awk -F: '{print $1,$3}' /etc/passwd |head -3
root 0
bin 1
daemon 2
2 /regular expression/: 仅处理能够模式匹配到的行,需要用/ /括起来
范例:
[root@CentOS8 test]#awk '/^UUID/' /etc/fstab
UUID=f2c173be-7848-43e9-9d0b-da0f1841f93f / xfs defaults 0 0
UUID=54ead45a-7577-4b54-9de2-501aef04207a /boot ext4 defaults 1 2
UUID=499afcaa-85a4-4b87-9223-20497b0bcf94 /data xfs defaults 0 0
UUID=80ee59c8-b184-4f49-9039-5150257143b8 none swap defaults 0 0
[root@CentOS8 test]#awk '/^UUID/{print $1}' /etc/fstab
UUID=f2c173be-7848-43e9-9d0b-da0f1841f93f
UUID=54ead45a-7577-4b54-9de2-501aef04207a
UUID=499afcaa-85a4-4b87-9223-20497b0bcf94
UUID=80ee59c8-b184-4f49-9039-5150257143b8
[root@CentOS8 test]#awk '/^UUID/{print $1,$2}' /etc/fstab
UUID=f2c173be-7848-43e9-9d0b-da0f1841f93f /
UUID=54ead45a-7577-4b54-9de2-501aef04207a /boot
UUID=499afcaa-85a4-4b87-9223-20497b0bcf94 /data
UUID=80ee59c8-b184-4f49-9039-5150257143b8 none
[root@CentOS8 test]#awk '!/^UUID/' /etc/fstab
#
# /etc/fstab
# Created by anaconda on Tue May 30 15:28:42 2023
#
# 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 relationalexpression: 关系表达式,结果为“真“才会被处理
[root@CentOS8 test]#awk '1' /etc/issue
Time at \t
Terminal on \l
\S
Kernel \r on an \m
[root@CentOS8 test]#awk '0' /etc/issue
[root@CentOS8 test]#awk 'as' /etc/issue #未加"",认为是个变量,而as变量未赋值,默认是空,即0,print
[root@CentOS8 test]#awk '"as"' /etc/issue
Time at \t
Terminal on \l
\S
Kernel \r on an \m
[root@CentOS8 test]#awk -v as="" 'as' /etc/issue
[root@CentOS8 test]#awk -v as="0" 'as' /etc/issue
[root@CentOS8 test]#awk -v as=0 'as' /etc/issue
[root@CentOS8 test]#awk '""' /etc/issue
[root@CentOS8 test]#awk '"0"' /etc/issue
Time at \t
Terminal on \l
\S
Kernel \r on an \m
例:
[root@CentOS8 test]#awk -F: 'i=1;j=1{print i,j}' /etc/passwd |head -6
root:x:0:0:root:/root:/bin/bash
1 1
bin:x:1:1:bin:/bin:/sbin/nologin
1 1
daemon:x:2:2:daemon:/sbin:/sbin/nologin
1 1
[root@CentOS8 test]#awk -F: 'i=1{print $0};j=1{print i,j}' /etc/passwd |head -6
root:x:0:0:root:/root:/bin/bash
1 1
bin:x:1:1:bin:/bin:/sbin/nologin
1 1
daemon:x:2:2:daemon:/sbin:/sbin/nologin
1 1
[root@CentOS8 test]#awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
joyce /bin/bash
nana /bin/bash
joycee /bin/bash
Tom /bin/bash
Alice /bin/bash
[root@CentOS8 test]#awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
root /bin/bash #~模糊匹配,bash为结尾的正则表达式
joyce /bin/bash
nana /bin/bash
joycee /bin/bash
Tom /bin/bash
Alice /bin/bash
4 line ranges: 行范围
不支持直接用行号,但可以使用变量NR间接表示行号
/pat1/,/pat2/ 不支持直接给出数字格式
例:
[root@CentOS8 test]#awk 'NR>=3 && NR<=6' /etc/passwd
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
sync:x:5:0:sync:/sbin:/bin/sync
[root@CentOS8 test]#sed -n '3,6p' /etc/passwd #sed实现
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
sync:x:5:0:sync:/sbin:/bin/sync
[root@CentOS8 test]#awk '/^b/,/^s/' /etc/passwd #挑出b开头到s开头的行
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
sync:x:5:0:sync:/sbin:/bin/sync
[root@CentOS8 test]#awk '/^b/,/^s/{print $0}' /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
sync:x:5:0:sync:/sbin:/bin/sync
5 BEGIN/END模式
[root@CentOS8 test]#awk -F: 'BEGIN{print "User UserID"} {print $1"\t"$3} END{print "END File"}' /etc/passwd
User UserID
root 0
bin 1
daemon 2
adm 3
...
pcp 974
END File
[root@CentOS8 test]#
语法:
if(condition){statement;...}[else statement]
if(condition1){statementl}else if(condition2){statement2}else if(condition3){statement3}...else{statement3}
使用场景:对awk取得的整行或某个字段做条件判断
范例:
[root@CentOS8 test]#awk -F: '{if($3>=1000)print "Common User:"$1,$3;else print "SysUser:"$1,$3}' /etc/passwd |tail -4
SysUser:apache 48
Common User:Tom 1003
Common User:Alice 1004
SysUser:pcp 974
[root@CentOS8 test]#awk 'BEGIN{test=100;if(test>90){print "very good" }else if(test>60){ print "good" }else{print "no pass"}}'
very good
[root@CentOS8 test]#awk 'BEGIN{test=80;if(test>90){print "very good" }else if(test>60){ print "good" }else{print "no pass"}}'
good
[root@CentOS8 test]#awk 'BEGIN{test=50;if(test>90){print "very good" }else if(test>60){ print "good" }else{print "no pass"}}'
no pass
例:实现将磁盘空间大于30以上的磁盘显示出来
[root@CentOS8 test]#df
Filesystem 1K-blocks Used Available Use% Mounted on
devtmpfs 970012 0 970012 0% /dev
tmpfs 998404 0 998404 0% /dev/shm
tmpfs 998404 9512 988892 1% /run
tmpfs 998404 0 998404 0% /sys/fs/cgroup
/dev/sda2 104806400 41650236 63156164 40% /
/dev/sda3 52403200 398776 52004424 1% /data
/dev/sda1 999320 194568 735940 21% /boot
tmpfs 199680 12 199668 1% /run/user/42
tmpfs 199680 0 199680 0% /run/user/0
[root@CentOS8 test]#df -h | awk -F"%" '/^\/dev\/sd/{print $1}' | awk -F" " '{if($NF>=30)print $1,$NF}'
/dev/sda2 40
[root@CentOS8 test]#df -h | awk -F' +|%' '/^\/dev\/sd/{if($5>=30)print $1,$5}'
/dev/sda2 40
语法:
switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
语法:
while (condition) {statement;....}
条件”真”,进入循环;条件”假”,退出循环
使用场景:
#内置函数length()返回字符数,而非字节数
[root@CentOS8 test]#awk 'BEGIN{print length("HEllo Babe")}'
10
[root@CentOS8 test]#awk 'BEGIN{print length("日本于24日排放核废水")}'
11
#逐个字段统计字段的字符个数
[root@CentOS7 ~]#awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-1160.71.1.el7.x86_64 36
root=UUID=d02bdd48-4a76-4680-991c-bc5769984946 46
ro 2
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-fa775acad508426696d0a36b0c9e008b 50
root=UUID=d02bdd48-4a76-4680-991c-bc5769984946 46
ro 2
rhgb 4
quiet 5
[root@CentOS7 ~]#awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=10)print $i,length($i);i++}}' /etc/grub2.cfg
/vmlinuz-3.10.0-1160.71.1.el7.x86_64 36
root=UUID=d02bdd48-4a76-4680-991c-bc5769984946 46
LANG=en_US.UTF-8 16
/vmlinuz-0-rescue-fa775acad508426696d0a36b0c9e008b 50
root=UUID=d02bdd48-4a76-4680-991c-bc5769984946 46
例:1+2+…100
[root@CentOS7 ~]#awk 'BEGIN{sum=0;i=1;while(i<=100){sum+=i;i++}print sum}'
5050
[root@CentOS7 ~]#for i in {1..100};do let sum+=i;done;echo $sum
5050
语法:
do {statement;...}while(condition)
意义:无论真假,至少执行一次循环体
例:1+2+…100
[root@CentOS7 ~]#awk 'BEGIN{total=0;i=1;do{total+=i;i++}while(i<=100);print total}'
5050
语法:
for(expr1;expr2;expr3) {statement;...}
常见用法:
for(variable assignment;condition;iteration process) {for-body}
特殊用法: 能够遍历数组中的元素
for(var in array) {for-body}
# var 每次循环都对应数组的下标
例:
[root@CentOS7 ~]#awk 'BEGIN{total=0;for(i=1;i<=100;i++){total+=i};print total}'
5050
格式:
continue [n] #中断本次循环
break [n] #中断整个循环
[root@CentOS7 ~]#awk 'BEGIN{total=0;for(i=1;i<=100;i++){if(i%2==0)continue;total+=i};print total}'
2500
[root@CentOS7 ~]#awk 'BEGIN{total=0;for(i=1;i<=100;i++){if(i==50)break;total+=i};print total}'
1225
next 可以提前结束对本行处理而直接进入下一行处理 (awk自身循环)
范例:
#只打印偶数行
[root@CentOS7 ~]#awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd|head -5
root 0
daemon 2
lp 4
shutdown 6
mail 8
awk的数组为关联数组
格式
array[index-expression]
范例:
weekdays["mon"]="Monday
index-expression
范例:
[root@CentOS7 ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday
例:
[root@CentOS8 test]#cat test2.txt
a
bb
ccc
a
b
11
ccc
d
11
22
[root@CentOS8 test]#awk '!line[$0]++' test2.txt
a
bb
ccc
b
11
d
22
#1、开始读入第一行line['a'],未定义,默认值是空,即line['a']=空
#2、因为line['a']=空,而前面有!取反,则!line['a']=真,则有隐藏的{print $0},即打印这一行a
#3、最后++,使line['a']=1
#同理,line['b']/line['ccc']也都变成1
#4、再次遇到a,则line['a']=1,前面!取反,则!line['a']=0,不打印这一行a,即跳过a,不过仍要++,后line['a']=2
#同理,遇到相同的b/ccc都会跳过
#因为每次都++,所以每次都会!取反导致不打印,这样就实现去重功能
[root@CentOS8 test]#awk '{!line[$0]++;print $0,line[$0]}' test2.txt
a 1
bb 1
ccc 1
a 2
b 1
11 1
ccc 2
d 1
11 2
22 1
a 3
例:判断数组索引是否存在
[root@CentOS8 test]#awk 'BEGIN{array["i"]="x";array["j"]="y"; print "i" in array,"j" in array}'
1 1
[root@CentOS8 test]#awk 'BEGIN{array["i"]="x";array["j"]="y"; print "i" in array,"m" in array}'
1 0
[root@CentOS8 test]#awk 'BEGIN{array["i"]="x";array["j"]="y"; print "n" in array,"m" in array}'
0 0
若要遍历数组中的每个元素,要使用for循环
for(var in array) {for-body}
注意: var会遍历array的每个索引
范例:遍历数组
[root@CentOS8 ~]#awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";weekdays["thu"]="Thursday";for(i in weekdays){print i":"weekdays[i]}}'
tue:Tuesday
thu:Thursday
mon:Monday
[root@CentOS8 ~]#awk 'BEGIN{weekdays[1]="Monday";weekdays[2]="Tuesday";weekdays[3]="Thursday";for(i in weekdays){print i":"weekdays[i]}}'
1:Monday
2:Tuesday
3:Thursday
[root@CentOS8 test]#awk -F: '{user[$1]=$3}END{for (i in user){print "username: "i,"uid:"user[i]}}' /etc/passwd|head -5
username: adm uid:3
username: rpc uid:32
username: dnsmasq uid:983
username: flatpak uid:977
username: radvd uid:75
例:显示主机连接状态出现的次数
[root@CentOS8 test]#ss -nt | awk 'NR!=1{print $1}' |sort|uniq -c
2 ESTAB
[root@CentOS8 test]#ss -nt | awk 'NR!=1{state[$1]++}END{for(i in state){print i,state[i]}}'
ESTAB 2
例:将日志中主机连接数超过1000的ip拉黑
[root@CentOS8 test]#awk '{ip[$1]++}END{for(i in ip){if(ip[i]>=1000){system("iptables -A INPUT -s "i" -j REJECT")}}}' file.log
#下面是只打印,而不拉黑
[root@CentOS8 test]#awk '{ip[$1]++}END{for(i in ip){if(ip[i]>=1000){print i,ip[i]}}}' file.log
rand(): 返回0和1之间一个随机数
srand(): 配合rand() 函数,生成随机数的种子
int(): 返回整数
范例:
#1、未加随机数种子,无法实现生成随机数
[root@CentOS8 test]#awk 'BEGIN{print rand()}'
0.924046
[root@CentOS8 test]#awk 'BEGIN{print rand()}'
0.924046
[root@CentOS8 test]#awk 'BEGIN{print rand()}'
0.924046
#2、添加srand()
[root@CentOS8 test]#awk 'BEGIN{srand();print rand()}'
0.550635
[root@CentOS8 test]#awk 'BEGIN{srand();print rand()}'
0.864986
#生成速度过快,会生成同一个随机数
#生成100以下的随机数,但是是小数
[root@CentOS8 test]#awk 'BEGIN{srand();print rand()*100}'
88.9721
[root@CentOS8 test]#awk 'BEGIN{srand();print rand()*100}'
88.9721
[root@CentOS8 test]#awk 'BEGIN{srand();print rand()*100}'
81.6498
#生成100以下的整数
[root@CentOS8 test]#awk 'BEGIN{srand();print int(rand()*100)}'
1
[root@CentOS8 test]#awk 'BEGIN{srand();print int(rand()*100)}'
5
[root@CentOS8 test]#awk 'BEGIN{srand();print int(rand()*100)}'
34
[root@CentOS8 test]#awk 'BEGIN{srand();print int(rand()*100)}'
34
[root@CentOS8 test]#awk 'BEGIN{srand();print int(rand()*100)}'
97
#生成10个100以下的随机整数
[root@CentOS8 test]#awk 'BEGIN{srand();for(i=1;i<=10;i++)print int(rand()*100)}'
85
73
89
23
4
99
48
87
26
7
[root@CentOS8 test]#awk 'BEGIN{srand();for(i=1;i<=10;i++)print int(rand()*100)}'
91
1
75
16
66
56
35
60
67
57
length([s]): 返回指定字符串的长度
sub(r,s,[t]): 对t字符串搜索r表示模式匹配的内容,并将第一个匹配内容替换为s
范例:
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
2008-08:08 08:08:08 #省略print $0
[root@centos8 ~]#echo "2008:08:08 08:08:08" | awk '{sub(/:/,"-",$1);print $0}'
2008-08:08 08:08:08
gsub(r,s,[t]): 对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
范例:
[root@CentOS8 test]#echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$1)'
2008-08-08 08:08:08 #省略print $0
[root@CentOS8 test]#echo "2008:08:08 08:08:08" | awk '{gsub(/:/,"-",$1);print $0}'
2008-08-08 08:08:08
split(s,array,[r]): 以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2....
范例:
[root@CentOS8 test]#netstat -tn
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 96 10.0.0.201:22 10.0.0.1:61841 ESTABLISHED
tcp 0 0 10.0.0.201:22 10.0.0.1:61842 ESTABLISHED
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63167 TIME_WAIT
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63171 ESTABLISHED
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63168 TIME_WAIT
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63172 ESTABLISHED
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63165 ESTABLISHED
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63174 ESTABLISHED
[root@CentOS8 test]#netstat -tn | awk '/tcp/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
10.0.0.1 8
system 函数: 可以awk中调用shell命令
空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用""引用起来
例:将日志中主机连接数超过1000的ip拉黑
[root@CentOS8 test]#awk '{ip[$1]++}END{for(i in ip){if(ip[i]>=1000){system("iptables -A INPUT -s "i" -j REJECT")}}}' file.log
#下面是只打印,而不拉黑
[root@CentOS8 test]#awk '{ip[$1]++}END{for(i in ip){if(ip[i]>=1000){print i,ip[i]}}}' file.log
格式:
function name ( parameter, parameter,...){
statements
return expression
}
例:取2个数中的较大值
[root@CentOS8 test]#cat func_max.awk
function max(x,y) {
x>y?var=x:var=y
return var
}
BEGIN{print max(a,b)}
[root@CentOS8 test]#awk -v a=33 -v b=22 -f func_max.awk
33
将awk程序写成脚本,直接调用或执行
例:
[root@CentOS8 test]#cat passwd_1.awk
{if($3>=1000)print $1,$3}
[root@CentOS8 test]#awk -F: -f passwd_1.awk /etc/passwd
nobody 65534
joyce 1000
nana 1001
joycee 1002
Tom 1003
Alice 1004
#把上面的直接写为脚本
[root@CentOS8 test]#cat passwd_2.awk
#!/bin/awk -f
#this is a awk script
{if($3>=1000)print $1,$3}
[root@CentOS8 test]#chmod +x passwd_2.awk
[root@CentOS8 test]#./passwd_2.awk -F: /etc/passwd
nobody 65534
joyce 1000
nana 1001
joycee 1002
Tom 1003
Alice 1004
向awk脚本传递参数
格式:
awkfile var=value var2=value2... Inputfile
注意: 在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通过-v 参数,让awk在执行BEGIN之前得到变量的值。命令行中每一个指定的变量都需要一个-V参数
范例:
[root@CentOS8 test]#cat passwd_3.awk
#!/bin/awk -f
#this is a awk script
{if($3>=min && $3<=max)print $1,$3}
[root@CentOS8 test]#./passwd_3.awk -F: min=100 max=200 /etc/passwd
systemd-resolve 193
rtkit 172
pulse 171
qemu 107
usbmuxd 113
#省略print $0
[root@centos8 ~]#echo “2008:08:08 08:08:08” | awk ‘{sub(/,“-”,$1);print $0}’
2008-08:08 08:08:08
###### **4.3.14.1.2.2 gsub**
```bash
gsub(r,s,[t]): 对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
范例:
[root@CentOS8 test]#echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$1)'
2008-08-08 08:08:08 #省略print $0
[root@CentOS8 test]#echo "2008:08:08 08:08:08" | awk '{gsub(/:/,"-",$1);print $0}'
2008-08-08 08:08:08
split(s,array,[r]): 以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2....
范例:
[root@CentOS8 test]#netstat -tn
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 96 10.0.0.201:22 10.0.0.1:61841 ESTABLISHED
tcp 0 0 10.0.0.201:22 10.0.0.1:61842 ESTABLISHED
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63167 TIME_WAIT
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63171 ESTABLISHED
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63168 TIME_WAIT
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63172 ESTABLISHED
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63165 ESTABLISHED
tcp6 0 0 10.0.0.201:9090 10.0.0.1:63174 ESTABLISHED
[root@CentOS8 test]#netstat -tn | awk '/tcp/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
10.0.0.1 8
system 函数: 可以awk中调用shell命令
空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用""引用起来
例:将日志中主机连接数超过1000的ip拉黑
[root@CentOS8 test]#awk '{ip[$1]++}END{for(i in ip){if(ip[i]>=1000){system("iptables -A INPUT -s "i" -j REJECT")}}}' file.log
#下面是只打印,而不拉黑
[root@CentOS8 test]#awk '{ip[$1]++}END{for(i in ip){if(ip[i]>=1000){print i,ip[i]}}}' file.log
格式:
function name ( parameter, parameter,...){
statements
return expression
}
例:取2个数中的较大值
[root@CentOS8 test]#cat func_max.awk
function max(x,y) {
x>y?var=x:var=y
return var
}
BEGIN{print max(a,b)}
[root@CentOS8 test]#awk -v a=33 -v b=22 -f func_max.awk
33
将awk程序写成脚本,直接调用或执行
例:
[root@CentOS8 test]#cat passwd_1.awk
{if($3>=1000)print $1,$3}
[root@CentOS8 test]#awk -F: -f passwd_1.awk /etc/passwd
nobody 65534
joyce 1000
nana 1001
joycee 1002
Tom 1003
Alice 1004
#把上面的直接写为脚本
[root@CentOS8 test]#cat passwd_2.awk
#!/bin/awk -f
#this is a awk script
{if($3>=1000)print $1,$3}
[root@CentOS8 test]#chmod +x passwd_2.awk
[root@CentOS8 test]#./passwd_2.awk -F: /etc/passwd
nobody 65534
joyce 1000
nana 1001
joycee 1002
Tom 1003
Alice 1004
向awk脚本传递参数
格式:
awkfile var=value var2=value2... Inputfile
注意: 在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通过-v 参数,让awk在执行BEGIN之前得到变量的值。命令行中每一个指定的变量都需要一个-V参数
范例:
[root@CentOS8 test]#cat passwd_3.awk
#!/bin/awk -f
#this is a awk script
{if($3>=min && $3<=max)print $1,$3}
[root@CentOS8 test]#./passwd_3.awk -F: min=100 max=200 /etc/passwd
systemd-resolve 193
rtkit 172
pulse 171
qemu 107
usbmuxd 113