awk文本工具

awk文本工具

目录

    • 1、文本处理工具grep
      • 1.1、grep[过滤出行]
      • 1.2、grep使用
      • 1.3、cut【截取列】
      • 1.4、练习1
      • 1.4、sort【排序,去重】
      • 1.5、uniq工具【去重】
      • 1.6、tee工具【结果屏幕输出一份,文件输出一份】
      • 1.6、diff工具【比较两个文件内容的异同】
      • 1.7、paste工具【合并文件行】
      • 1.8、tr工具【用于字符的转换】
      • 1.9、练习2
      • 1.10、练习3
    • 2、文本处理工具sed
        • ① 对文件进行增、删、改、查操作
        • ③ 其他命令
    • 3、文本处理工具awk
      • awk原理
      • awk使用进阶
      • awk的脚本编程
      • awk统计案例
        • 1. 任务/背景
        • 2. 具体要求
        • 3. 涉及知识点

1、文本处理工具grep

Linux中最重要的三个命令在业界被称为“三剑客”,它们是awk,sed,grep
https://blog.csdn.net/sj349781478/article/details/82930982

1.1、grep[过滤出行]

grep是行过滤工具,用于根据关键字进行行过滤。

语法:grep 【可选项】 ‘关键字’ 文件名
常见选项:
-i 忽略字符大小写
-v 查找不包含指定内容的行,反向选择
-w 按单词搜索
-o 打印匹配的关键字
-c 统计匹配到的次数
-n 显示行号
-r 逐层遍历目录查找
-A 显示匹配行以及后面多少行
-B: 显示匹配行及前面多少行
-C: 显示匹配行前后多少行
-l:只列出匹配的文件名
-L:列出不匹配的文件名
-e: 使用正则匹配
-E:使用扩展正则匹配
^key:以关键字开头
keyKaTeX parse error: Expected group after '^' at position 42: …d group after '^̲' at position 9…:匹配空行
--color=auto :可以将找到的关键词部分加上颜色的显示

1.2、grep使用

1、高亮:grep --color=auto 'error' adapter.log

临时设置:alias grep='grep --color=auto'
永久高亮:

vi /etc/bashrc 
最后添加:alias  grep='grep --color=auto'
source /etc/bashrc 

设置完后,这样也能高亮:grep 'error' adapter.log

2、过滤行并且显示行号
过滤出包含root字符串的行并且显示行号

[root@localhost ~]# grep -n 'root' test
3:2020-10-28 21:21:37.887 [main] INFO  org.apache.zookeeper.ZooKeeper - Client environment:user.dir=/root/canal/adapter/bin

3、过滤出包含root字符串的行忽略大小写,并且显示行号

[root@localhost ~]# grep -ni 'root' test
2:2020-10-28 21:22:18.370 ROOT  [main-SendThread(localhost:2181)] WARN  org.apacheEE.zookeeper.ClientCnxn - Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
3:2020-10-28 21:21:37.887 [main] INFO  org.apache.zookeeper.ZooKeeper - Client environment:user.dir=/root/canal/adapter/bina

4、过滤出文件中以root开头的行

[root@localhost ~]# grep '^root' test
root2020-10-28 21:22:18.370 [main-SendThread(localhost:2181)] WARN  org.apache.zookeeper.ClientCnxn - Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect

5、过滤出文件中以xxx结尾的行

[root@localhost ~]# grep 'reconnect$' test
root2020-10-28 21:22:18.370 [main-SendThread(localhost:2181)] WARN  org.apache.zookeeper.ClientCnxn - Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
2020-10-28 21:22:18.370 ROOT  [main-SendThread(localhost:2181)] WARN  org.apacheEE.zookeeper.ClientCnxn - Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect

6、过滤出文件中不以xxx开头的行
使用-v取反,即可

[root@localhost ~]# grep -niv '^root' test
2:2020-10-28 21:22:18.370 ROOT  [main-SendThread(localhost:2181)] WARN  org.apacheEE.zookeeper.ClientCnxn - Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
3:2020-10-28 21:21:37.887 [main] INFO  org.apache.zookeeper.ZooKeeper - Client environment:user.dir=/root/canal/adapter/bina

7、过滤出文件中以xxx开头的前x行,后x行
-B x 过滤出关键字的前几行

[root@localhost ~]# grep -n -B 1 '^ftp' test
3-2020-10-28 21:21:37.887 [main] INFO  org.apache.zookeeper.ZooKeeper - Client environment:user.dir=/root/canal/adapter/bina
4:ftp2020-10-28 21:21:37.887 [main] INFO  org.apache.zookeeper.ZooKeeper - Client environment:user.dir=/root/canal/adapter/bina

-A x 过滤出关键字的后几行
-C x 过滤出关键字的前后几行

8、根据单词去过滤出文件中的行
-w 根据单词去过滤行。

[root@localhost ~]# grep -w 'hello' test
hello world 

helloworld是过滤出不出来的。

9、统计文件中某个单词出现的次数

[root@localhost ~]# grep -o "a"  test  | wc -l
30

-o 打印匹配的关键字
| 将结果输出给下一个命令
wc 将计算指定文件的行数、字数,以及字节数。
-l 只显示行数。

10、在大日志文件中搜索关键字,最后/最开始出现位置

1、先查出关键字,前后一行的数据:grep -C 1 ‘error’ test
在这里插入图片描述
2、然后将结果通过|,输出给后面的tail命令去统计:grep -C 1 'error' test | tail -2
tail -2 要显示文件的最后2行

在这里插入图片描述

1.3、cut【截取列】

grep是行的过滤,cut是列的截取

语法:cut 选项 文件名
-c: 以字符为单位进行分割,截取
-d: 自定义分隔符,默认为制表符\t
-f: 与-d一起使用,指定截取哪个区域

1、截取号的第一列
-d:表示使用冒号分割
-f1 表示取分割的第一列

[root@localhost ~]# cut -d: -f1 test
aaaaaaaaaaaaaaaaaaaaaaa
root2020-10-28 21
2020-10-28 21
2020-10-28 21
ftp2020-10-28 21
hello world 
helloworld

2、截取号的第一列和第七列

[root@localhost ~]# cut -d: -f1,7  test
aaaaaaaaaaaaaaaaaaaaaaa
root2020-10-28 21: Session
2020-10-28 21
2020-10-28 21
ftp2020-10-28 21
hello world 
helloworld

3、截取从第一个字符到第五个字符

[root@localhost ~]# cut -c1-5 test
aaaaa
root2
2020-
2020-
ftp20
hello
hello

-c10- :表示从第十个字符开始全部截取

注意:列的截取,使用变量的时候也可以截取

#第8位开始,截取4位,索引从0开始
${luck_num:7:4}

1.4、练习1

如何过滤出运行级别?

1、获取运行级别的方法

  • runlevel
  • [root@localhost ~]# cat /etc/inittab

2、解决:
使用cut

[root@localhost ~]# runlevel
N 3
[root@localhost ~]# runlevel | cut -d ' ' -f2  
3
[root@localhost ~]# runlevel | cut -c3
3

使用grep

[root@localhost ~]# grep '^id'  /etc/inittab | cut -c4
3
[root@localhost ~]# grep -v '^#'  /etc/inittab | cut -c4
3
[root@localhost ~]# grep 'initdefault:$'  /etc/inittab | cut -c4
3

1.4、sort【排序,去重】

sort工具用于排序;它将文件的每一行作为一个单位,从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。

语法和选项:

-u :去除重复行
-r :降序排列,默认是升序
-o : 将排序结果输出到文件中,类似重定向符号>
-n :以数字排序,默认是按字符排序
-t :分隔符
-k :第N-b :忽略前导空格。
-R :随机排序,每次运行的结果均不同

使用例子:
1、对文件排序
-n 使用数字排序
-t:使用冒号作为分隔符号
-k2 表示按照第二列来排序

[root@localhost ~]# sort -n -t: -k2 1.txt 
asdas:111
123:123
ss123:222
asd:333
456:456
789:789

1.5、uniq工具【去重】

uniq用于去除连续重复行

常见选项:

-i: 忽略大小写
-c: 统计重复行次数
-d:只显示重复行

实例:uniq只去除连续重复的行

[root@localhost ~]# uniq 1.txt
123:123
456:456
789:789
asdas:111
ss123:222
asd:333
456:456
[root@localhost ~]# cat 1.txt 
123:123
123:123
456:456
789:789
asdas:111
ss123:222
asd:333
456:456

1.6、tee工具【结果屏幕输出一份,文件输出一份】

tee工具是从标准输入读取并写入到标准输出和文件,即:双向覆盖重定向(屏幕输出|文本输入),简单说,就是屏幕打印一份,文件里一份

  • 标准输入:键盘输出的就是,文件的内容也是
  • 标准输出:屏幕上,文件
  • 默认是覆盖,想要追加,使用选项

>:表示覆盖原文件内容
>>:这个是将输出内容追加到目标文件中。如果文件不存在,就创建文件;如果文件存在,则将新的内容追加到那个文件的末尾,该文件中的原有内容不受影响;

区别:tee可以把一份数据同时写入几个文件中,而>>只能把一份数据写入到一个文件中;

选项:
-a 双向追加重定向

使用例子:
1、将标准的输入读取并写到文件中,默认覆盖

[root@localhost ~]# echo hello world |tee  1.txt
hello world
[root@localhost ~]# cat 1.txt
hello world

2、追加

[root@localhost ~]# echo hello world |tee -a  1.txt
hello world
[root@localhost ~]# cat 1.txt
hello world
hello world

1.6、diff工具【比较两个文件内容的异同】

diff工具用于逐行比较文件的不同。
注意:diff描述两个文件不同的方式是告诉我们怎样改变第一个文件之后与第二个文件匹配

语法:

diff [选项] 文件1 文件2

常用选项:

-b不检查空格
-B不检查空白行
-i不检查大小写
-w忽略所有的空格
--normal正常格式显示(默认)
-c上下文格式显示
-u合并格式显示

1、正常模式:
diff目的:file1如何改变才能和file2匹配
比较难看懂

[root@MissHou ~]# diff file1 file2
1c1,2					第一个文件的第1行需要改变(c=change)才能和第二个文件的第12行匹配			
< aaaa				小于号"<"表示左边文件(file1)文件内容
---					---表示分隔符
> aaa					大于号">"表示右边文件(file2)文件内容
> hello
3d3					第一个文件的第3行删除(d=delete)后才能和第二个文件的第3行匹配
< hello world
5d4					第一个文件的第5行删除后才能和第二个文件的第4行匹配
< 333
6a6,7					第一个文件的第6行增加(a=add)内容后才能和第二个文件的第67行匹配
> 333					需要增加的内容在第二个文件里是333和world
> world
[root@localhost shellDemo]# cat file1
aaaa
111
hello world
222
333
bbb
[root@localhost shellDemo]# cat file2
aaa
hello
111
222
bbb
333
world

2、上下文格式显示:

[root@MissHou ~]# diff -c file1 file2
前两行主要列出需要比较的文件名和文件的时间戳;文件名前面的符号***表示file1,---表示file2
*** file1       2019-04-16 16:26:05.748650262 +0800
--- file2       2019-04-16 16:26:30.470646030 +0800
***************	我是分隔符
*** 1,6 *******开头表示file1文件,1,6表示16! aaaa				!表示该行需要修改才与第二个文件匹配
  111
- hello world		-表示需要删除该行才与第二个文件匹配
  222
- 333					-表示需要删除该行才与第二个文件匹配
  bbb
--- 1,7 -------开头表示file2文件,1,7表示17! aaa				表示第一个文件需要修改才与第二个文件匹配
! hello				表示第一个文件需要修改才与第二个文件匹配
  111
  222
  bbb
+ 333				表示第一个文件需要加上该行才与第二个文件匹配
+ world				表示第一个文件需要加上该行才与第二个文件匹配

3、合并格式显示:

[root@MissHou ~]# diff -u file1 file2
前两行主要列出需要比较的文件名和文件的时间戳;文件名前面的符号---表示file1,+++表示file2
--- file1       2019-04-16 16:26:05.748650262 +0800
+++ file2       2019-04-16 16:26:30.470646030 +0800
@@ -1,6 +1,7 @@
-aaaa
+aaa
+hello
 111
-hello world
 222
-333
 bbb
+333
+world

4、比较两个文件,并把文件2的不同的地方,以打补丁的方式,打到文件1中去,使两个文件的内容一样

先找出文件的不同,然后将结果输出到一个文件file3,file3就是补丁文件
diff -u file1 file2 > file3
打补丁
patch file1 file3
验证:
[root@localhost shellDemo]# diff file1 file2
[root@localhost shellDemo]# cat file1
aaa
hello
111
222
bbb
333
world
[root@localhost shellDemo]# cat file2
aaa
hello
111
222
bbb
333
world

5、比较两个目录不同

默认情况下也会比较两个目录里相同文件的内容
[root@MissHou  tmp]# diff dir1 dir2
diff dir1/file1 dir2/file1
0a1
> hello
Only in dir1: file3
Only in dir2: test1
如果只需要比较两个目录里文件的不同,不需要进一步比较文件内容,需要加-q选项
[root@MissHou  tmp]# diff -q dir1 dir2
Files dir1/file1 and dir2/file1 differ
Only in dir1: file3
Only in dir2: test1

1.7、paste工具【合并文件行】

paste工具用于合并文件行

常用选项:
-d:自定义间隔符,默认是tab
-s:串行处理,非并行

例:
默认是以制表符分割

[root@localhost shellDemo]# paste file1 file2
aaa     aaa
hello   hello
111     111
222     222
bbb     bbb
333     333
world   world

指定分割符号:

[root@localhost shellDemo]# paste -d:  file1 file2
aaa:aaa
hello:hello
111:111
222:222
bbb:bbb
333:333
world:world

串行处理:

[root@localhost shellDemo]# paste -s  file1 file2
aaa     hello   111     222     bbb     333     world
aaa     hello   111     222     bbb     333     world

1.8、tr工具【用于字符的转换】

tr用于字符转换,替换和删除;主要用于删除文件中控制字符或进行字符转换

语法:

用法1:命令的执行结果交给tr处理,其中string1用于查询,string2用于转换处理

commands|tr ‘string1’ ‘string2’

用法2:tr处理的内容来自文件,记住要使用"<"标准输入

tr ‘string1’ ‘string2’ < filename

用法3:匹配string1进行相应操作,如删除操作

tr [options] ‘string1’ < filename

常用选项:

-d 删除字符串1中所有输入字符。
-s 删除所有重复出现字符序列,只保留第一个;即将重复出现字符串压缩为一个字符串

常匹配字符串:

a-z或[:lower:] 匹配所有小写字母
A-Z[:upper:] 匹配所有大写字母
0-9[:digit:] 匹配所有数字
[:alnum:] 匹配所有字母和数字
[:alpha:] 匹配所有字母
[:blank:] 所有水平空白
[:punct:] 匹配所有标点符号
[:space:] 所有水平或垂直的空格
\n Ctrl-J  	换行
\r Ctrl-M   回车
\t Ctrl-I  	tab键

例子:
1、把文件中的字母全部转成大写,并输出到控制台

[root@localhost shellDemo]# tr 'a-z' 'A-Z' <file1 
AAA
HELLO
111
222
BBB
333
WORLD
[root@localhost shellDemo]# tr [:lower:]  'A-Z' <file1 
AAA
HELLO
111
222
BBB
333
WORLD

2、把文件中的数字全部转成@,并输出到控制台

[root@localhost shellDemo]# tr '0-9' '@' <file1 
aaa
hello
@@@
@@@
bbb
@@@

3、把文件中的:/全部转成#,并输出到控制台

[root@localhost shellDemo]# tr ':/' '#' <file1
aaa
hello
111
222
bbb
333
world
54#asd#12123
00#olosd#111

4、删除文件中的小写字母

[root@localhost shellDemo]# tr -d 'a-z' <file1

111
222

333

54:/12123
00:/111

1.9、练习2

截取出当前主机的ip,子网掩码和网络地址。

实现:
ifconfig ens33:查看ip,子网掩码和网络地址
grep 'netmask':筛选出含’netmask’字符串的行
tr -d 'a-zA-Z':删除文件中的小写字母大写字母
tr ' ' '\n':将空格替换为换行
grep -v '^$':找出所有的空行^$,然后取反

[root@localhost shellDemo]# ifconfig ens33 | grep 'netmask'| tr -d 'a-zA-Z' | tr ' ' '\n' | grep -v '^$'
192.168.169.129
255.255.255.0
192.168.169.255

获取物理地址:
tr -s ' ' :压缩空格
cut -d' ' -f3:截取列

[root@localhost shellDemo]# ifconfig ens33 |grep 'ether' | tr -s ' '| cut -d' ' -f3
00:0c:29:18:27:a5

1.10、练习3

将系统中所有普通用户的用户名、密码和默认shell保存到一个文件中,要求用户名密码和默认shell之间tab键分割

1、查看用户
UID来区分普通用户和系统用户,即UID大于999的为普通用户,否则为系统用户。

[root@localhost shellDemo]# cat /etc/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
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
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:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
lzh:x:1000:1000:lzh:/home/lzh:/bin/bash
sonar:x:1001:1001::/home/sonar:/bin/bash
dockerroot:x:998:995:Docker User:/var/lib/docker:/sbin/nologin

2、编写
grep 'bash$':过滤出所有一bash结尾的行
grep -v 'root':过滤掉root用户
cut -d: -f1,2,7:以冒号来截取列,截取1,2,7列
tr ':' '\t' :将冒号换成制表符
tee abc.txt:输出到文件同时控制台输出看一下

[root@localhost shellDemo]# grep 'bash$' /etc/passwd | grep -v 'root' |cut -d: -f1,2,7| tr  ':' '\t' | tee abc.txt
lzh     x       /bin/bash
sonar   x       /bin/bash
[root@localhost shellDemo]# cat abc.txt 
lzh     x       /bin/bash
sonar   x       /bin/bash

2、文本处理工具sed

1、sed用来做啥?
sed是Stream Editor(流编辑器)的缩写,简称流编辑器;用来处理文件的。

文件编辑器有哪些?
Windows:notepad++、editplus、ultraedit
linux:vim、vi、gedit、nano、emacs
有时候要在脚本里处理文件,通过文件编辑器的话,还要去与文件编辑器交互,比较麻烦,在脚本中处理文件,一般使用sed工具,sed可以直接修改文件,不需要交互

2、sed如何处理文件?
sed是一行一行读取文件内容并按照要求进行处理,把处理后的结果输出到屏幕
awk文本工具_第1张图片

  1. 首先sed读取文件中的一行内容,把其保存在一个临时缓存区中(也称为模式空间)
  2. 然后根据需求处理临时缓冲区中的行,完成后把该行发送到屏幕上

总结:

  1. 由于sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会直接修改原文件
  2. sed主要用来自动编辑一个或多个文件;简化对文件的反复操作,对文件进行过滤和转换操作

3、sed使用方法介绍
sed常见的语法格式有两种,一种叫命令行模式,另一种叫脚本模式。

命令行模式:

sed  [options]    '处理动作'   文件名
  • 常用选项
选项 说明 备注
-e 进行多项(多次)编辑
-n 取消默认输出 不自动打印模式空间
-r 使用扩展正则表达式
-i 原地编辑(修改源文件)
-f 指定sed脚本的文件名
  • 常见处理动作

丑话说在前面:以下所有的动作都要在单引号

动作 说明 备注
‘p’ 打印
‘i’ 在指定行之前插入内容 类似vim里的大写O
‘a’ 在指定行之后插入内容 类似vim里的小写o
‘c’ 替换指定行所有内容
‘d’ 删除指定行

使用例子:打印文件内容

#打印所有内容
[root@localhost shellDemo]# sed '' a.txt 
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
298374837483
172.16.0.254
10.1.1.1
#默认输出和p打印
[root@localhost shellDemo]# sed 'p' a.txt 
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
298374837483
298374837483
172.16.0.254
172.16.0.254
10.1.1.1
10.1.1.1
#取消默认输出
[root@localhost shellDemo]# sed  -n 'p' a.txt 
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
298374837483
172.16.0.254
10.1.1.1
#只打印第二行
[root@localhost shellDemo]# sed  -n '2p' a.txt 
bin:x:1:1:bin:/bin:/sbin/nologin
#只打印1-5行
[root@localhost shellDemo]# sed  -n '1,5p' a.txt 
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@localhost shellDemo]# sed  -n '$p' a.txt 
10.1.1.1

① 对文件进行增、删、改、查操作

增加文件内容:
注:输出的结果显示的是增加的了,但是源文件是没变的

#在第二行之前插入内容xx
[root@localhost shellDemo]# sed '2ixx' 1.txt 
#在所有行之前插入内容xx
[root@localhost shellDemo]# sed 'ixx' 1.txt 
#在所有行之前插入两行内容
[root@localhost shellDemo]# sed 'i66\n77' 1.txt 
#在1-3行后,插入zzz
[root@localhost shellDemo]# sed '1,3azzz' 1.txt 

删除文件内容:

#删除文件第一行
[root@localhost shellDemo]# sed '1d' 1.txt 
#删除1-3行
[root@localhost shellDemo]# sed '1,3d' 1.txt 
#删除文件最后一行
[root@server ~]# sed '$d' a.txt						

修改文件内容:

[root@server ~]# sed '5chello world' a.txt 		替换文件第5行内容
[root@server ~]# sed 'chello world' a.txt 		替换文件所有内容
[root@server ~]# sed '1,5chello world' a.txt 	替换文件1到5号内容为hello world
[root@server ~]# sed '/^user01/c888888' a.txt	替换以user01开头的行

② 对文件进行搜索替换操作:

语法:sed 选项 s/搜索的内容/替换的内容/动作 需要处理的文件

其中,s表示search搜索;斜杠/表示分隔符,可以自己定义;动作一般是打印p和全局替换g

#搜索root并替换成ROOT
[root@server ~]# sed -n 's/root/ROOT/p' 1.txt 
#搜索root并全局替换成ROOT
[root@server ~]# sed -n 's/root/ROOT/gp' 1.txt 
#搜索#开头的行,并把#替换成空格
[root@server ~]# sed -n 's/^#//gp' 1.txt 
#要搜索的字符串本来就有/,可以使用@作为分隔符(自己定义,前后一致就可以),当然也可以直接使用转义符\
[root@server ~]# sed -n 's@/sbin/nologin@itcast@gp' a.txt
#注释掉文件的1-5行内容,^表示行首
[root@server ~]# sed -n '1,5s/^/#/p' a.txt 		

③ 其他命令

命令 解释 备注
r 从另外文件中读取内容
w 内容另存为
& 保存查找串以便在替换串中引用 相同
= 打印行号
对所选行以外的所有行应用命令,放到行数之后 ‘1,5!’
q 退出
#把文件1.txt的内容,插入到a.txt第三行之后
[root@localhost shellDemo]# sed '3r /root/shellDemo/1.txt' a.txt
#将文件1.txt的1-3行,另存为到2.txt中
[root@localhost shellDemo]# sed '1,3w 2.txt' 1.txt 
#将1,3行的#替换成空格
[root@localhost shellDemo]# sed -n '1,3s/#//p' 1.txt

3、文本处理工具awk

1、awk概述

  • awk是一种编程语言,主要用于在linux/unix下对文本和数据进行处理,是linux/unix下的一个工具。数据可以来自标准输入、一个或多个文件,或其它命令的输出。
  • awk的处理文本和数据的方式:逐行扫描文件,默认从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。
  • awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。
  • gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。

2、awk能干啥?

  1. awk用来处理文件和数据的,是类unix下的一个工具,也是一种编程语言
  2. 可以用来统计数据,比如网站的访问量,访问的IP量等等
  3. 支持条件判断,支持for和while循环

3、awk使用方式
命令行模式使用:

awk 选项 '命令部分' 文件名

特别说明:
引用shell变量需用双引号引起

常用选项介绍

  • -F 定义字段分割符号,默认的分隔符是空格
  • -v 定义变量并赋值

命名部分说明

  • 正则表达式,地址定位
'/root/{awk语句}'				sed中: '/root/p'
'NR==1,NR==5{awk语句}'			sed中: '1,5p'
'/^root/,/^ftp/{awk语句}'  	sed中:'/^root/,/^ftp/p'
  • {awk语句1;awk语句2;…}
'{print $0;print $1}'		sed中:'p'
'NR==5{print $0}'				sed中:'5p'
注:awk命令语句间用分号间隔
  • BEGIN…END…
'BEGIN{awk语句};{处理中};END{awk语句}'
'BEGIN{awk语句};{处理中}'
'{处理中};END{awk语句}'

脚本模式使用:

脚本编写

#!/bin/awk -f 		定义魔法字符
以下是awk引号里的命令清单,不要用引号保护命令,多个命令用分号间隔
BEGIN{FS=":"}
NR==1,NR==3{print $1"\t"$NF}
...

脚本执行

方法1:
awk 选项 -f awk的脚本文件  要处理的文本文件
awk -f awk.sh filename

sed -f sed.sh -i filename

方法2:
./awk的脚本文件(或者绝对路径) 要处理的文本文件
./awk.sh filename

./sed.sh filename

4、awk内部相关变量

变量 变量说明 备注
$0 当前处理行的所有记录
$1,$2,$3…$n 文件中每行以间隔符号分割的不同字段 awk -F: ‘{print $1,$3}’
NF 当前记录的字段数(列数) awk -F: ‘{print NF}’
$NF 最后一列 $(NF-1)表示倒数第二列
FNR/NR 行号
FS 定义间隔符 ‘BEGIN{FS=":"};{print $1,$3}’
OFS 定义输出字段分隔符,默认空格 ‘BEGIN{OFS="\t"};print $1,$3}’
RS 输入记录分割符,默认换行 ‘BEGIN{RS="\t"};{print $0}’
ORS 输出记录分割符,默认换行 ‘BEGIN{ORS="\n\n"};{print $1,$3}’
FILENAME 当前输入的文件名

使用例子:

打印出文件中的所有行
[root@localhost shellDemo]# awk '{print $0}' 1.txt 
打印出文件中的1-3行
[root@localhost shellDemo]# awk 'NR==1,NR==3{print $0}' 1.txt 
[root@localhost shellDemo]# awk 'NR>=1 && NR<=3{print $0}' 1.txt 
打印出文件中的1或者3行
[root@localhost shellDemo]# awk 'NR==1 || NR==3{print $0}' 1.txt 
以:为分隔符,打印第一列,倒数第二列和最后一列
[root@localhost shellDemo]# awk -F: '{print $1,$(NF-1),$NF}' 1.txt 
以:为分割符,查看一下每行有几列
[root@localhost shellDemo]# awk -F: '{print NF}' 1.txt 

常用内置变量举例:

打印冒号分割时,第一列和倒数第二列
# awk -F: '{print $1,$(NF-1)}' 1.txt
以:为分隔符,打印第一列,倒数第二列和最后一列,还有列数
# awk -F: '{print $1,$(NF-1),$NF,NF}' 1.txt
在文件1.txt,匹配到包含root的行,并打印出来
# awk '/root/{print $0}' 1.txt
和上面的是一个意思
# awk '/root/' 1.txt
以冒号分割,在文件中,包含root关键字的那一行,打印出第一列和最后一列
# awk -F: '/root/{print $1,$NF}' 1.txt 
以冒号分割,在文件中,包含root关键字的那一行,打印出所有列
# awk -F: '/root/{print $0}' 1.txt      
打印一到五行
# awk 'NR==1,NR==5' 1.txt 
和上面的一样
# awk 'NR==1,NR==5{print $0}' 1.txt
打印一到五行和一到五行中包含root关键字的行
# awk 'NR==1,NR==5;/^root/{print $0}' 1.txt 
第一次打印,是因为符合一到五行的条件
root:x:0:0:root:/root:/bin/bash
第二次打印是因为包含root关键字,符合第二个条件
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

常用变量OPS和FS:

以冒号为分隔符,打印第一列和最后一列,默认每列以空格分隔打印
[root@localhost shellDemo]# awk -F: '{print $1 ,$NF}' 1.txt 
xroot /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
u5 /bin/bash
ntp /sbin/nologin
yunwei /bin/bash
以冒号为分隔符,打印第一列和最后一列,按照自定义的字符分隔打印
[root@localhost shellDemo]# awk -F: 'BEGIN{OFS="@"};{print $1 ,$NF}' 1.txt 
xroot@/bin/bash
bin@/sbin/nologin
daemon@/sbin/nologin
u5@/bin/bash
ntp@/sbin/nologin
yunwei@/bin/bash
和上面的一样
[root@localhost shellDemo]# awk 'BEGIN{FS=":"; OFS="@"};{print $1 ,$NF}' 1.txt 
xroot@/bin/bash
bin@/sbin/nologin
daemon@/sbin/nologin
u5@/bin/bash
ntp@/sbin/nologin
yunwei@/bin/bash
和上面的一样
[root@localhost shellDemo]# awk 'BEGIN{FS=":"};{print $1"@"$NF}' 1.txt 
xroot@/bin/bash
bin@/sbin/nologin
daemon@/sbin/nologin
u5@/bin/bash
ntp@/sbin/nologin
yunwei@/bin/bash
[root@localhost shellDemo]# awk 'BEGIN{FS=":"};{print "用户名:" $1 " shell解释器:" $NF}' 1.txt 

了解RS和ORS变量

[root@localhost shellDemo]# cat 1.txt 
xroot:x:0:0:root:/root:/bin/bash        bbb     ccc     ddd
以制表符\t作为,换行符,并取每一行的第一列
[root@localhost shellDemo]# awk -F: 'BEGIN{RS="\t"};{print $1}' 1.txt 
xroot
bbb
ccc
ddd

awk原理

awk -F: '{print $1,$3}' /etc/passwd

  1. awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符(RS)结束

  2. 每行被间隔符 :(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始

    问:awk如何知道用空格来分隔字段的呢?

    答:因为有一个内部变量FS来确定字段分隔符。初始时,FS赋为空格

  3. awk使用print函数打印字段,打印出来的字段会以空格分隔,因为$1,$3之间有一个逗号。逗号比较特殊,它映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格

  4. awk处理完一行后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕

awk使用进阶

1、 格式化输出printprintf
print函数 类似echo “hello world”,会换行
printf函数 类似echo -n 不会换行

#默认使用空格分隔
[root@localhost shellDemo]# date|awk '{print "月份:" $2 "\n年份:" $1 }'
月份:12月
年份:2020年
[root@localhost shellDemo]# awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}'  /etc/passwd
root            x          0              
bin             x          1  
%s 字符类型  strings			%-20s
%d 数值类型	
占15字符
- 表示左对齐,默认是右对齐
printf默认不会在行尾自动换行,加\n

2、awk变量定义:

设置变量并调用变量
[root@localhost shellDemo]# awk -v NUM=3 -F: 'BEGIN {print NUM}'
3
注意:
awk中调用定义的变量不需要加$,加了就表示第几列

3、awk中BEGIN…END使用
​ ①BEGIN:表示在程序开始前执行
​ ②END :表示所有文件处理完后执行
​ ③用法:'BEGIN{开始处理之前};{处理中};END{处理结束后}'
例如:

[root@localhost shellDemo]# awk 'BEGIN{ FS=":";print "Login_shell\tLogin_home\n*******************"};{print $NF"\t"$(NF-1)};END{print "************************"}' 1.txt
Login_shell     Login_home
*******************
/bin/bash       /root
/sbin/nologin   /bin
/sbin/nologin   /sbin
/sbin/nologin   /var/adm
/sbin/nologin   /var/spool/lpd
/bin/sync       /sbin
/sbin/shutdown  /sbin
/sbin/halt      /sbin
/sbin/nologin   /var/spool/mail
/sbin/nologin   /root
************************

awk -F: ‘BEGIN{print"u_name\t\th_dir\t\tshell\n***************************"};{printf “%-20s %-20s %-20s\n”, 1 < / s p a n > , < s p a n c l a s s = " t o k e n v a r i a b l e " > < s p a n c l a s s = " t o k e n v a r i a b l e " > 1, 1</span>,<spanclass="tokenvariable"><spanclass="tokenvariable">(NF-1),$NF};END{print “****************************”}’ 1.txt

4、 awk和正则的综合运用

运算符 说明
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
~ 匹配
!~ 不匹配
! 逻辑非
&& 逻辑与
|| 逻辑或

举例说明

从第一行开始匹配到以lp开头行
awk -F: 'NR==1,/^lp/{print $0 }' passwd  
从第一行到第5行          
awk -F: 'NR==1,NR==5{print $0 }' passwd
从以lp开头的行匹配到第10行       
awk -F: '/^lp/,NR==10{print $0 }' passwd 
从以root开头的行匹配到以lp开头的行       
awk -F: '/^root/,/^lp/{print $0}' passwd
打印以root开头或者以lp开头的行            
awk -F: '/^root/ || /^lp/{print $0}' passwd
awk -F: '/^root/;/^lp/{print $0}' passwd
显示5-10行   
awk -F':' 'NR>=5 && NR<=10 {print $0}' /etc/passwd     
awk -F: 'NR<10 && NR>5 {print $0}' passwd 

打印30-39行以bash结尾的内容:
[root@MissHou shell06]# awk ‘NR>=30 && NR<=39 && 0   / b a s h 0 ~ /bash 0 /bash/{print $0}’ passwd
stu1❌500:500::/home/stu1:/bin/bash
yunwei❌501:501::/home/yunwei:/bin/bash
user01❌502:502::/home/user01:/bin/bash
user02❌503:503::/home/user02:/bin/bash
user03❌504:504::/home/user03:/bin/bash

[root@MissHou shell06]# awk ‘NR>=3 && NR<=8 && /bash$/’ 1.txt
stu7❌1007:1007::/rhome/stu7:/bin/bash
stu8❌1008:1008::/rhome/stu8:/bin/bash
stu9❌1009:1009::/rhome/stu9:/bin/bash

打印文件中1-5并且以root开头的行
[root@MissHou shell06]# awk ‘NR>=1 && NR<=5 && $0 ~ /^root/{print $0}’ 1.txt
root❌0:0:root:/root:/bin/bash
[root@MissHou shell06]# awk ‘NR>=1 && NR<=5 && $0 !~ /^root/{print $0}’ 1.txt
bin❌1:1:bin:/bin:/sbin/nologin
daemon❌2:2:daemon:/sbin:/sbin/nologin
adm❌3:4:adm:/var/adm:/sbin/nologin
lp❌4:7:lp:/var/spool/lpd:/sbin/nologin

理解;号和||的含义:
[root@MissHou shell06]# awk ‘NR>=3 && NR<=8 || /bashKaTeX parse error: Expected 'EOF', got '#' at position 145: …token comment">#̲ awk 'NR>=3 …/’ 1.txt

打印IP地址
[root@localhost shellDemo]# ifconfig ens33|awk ‘NR==2{print $2}’
192.168.169.129
# ifconfig eth0|awk ‘NR>1 {print $2}’|awk -F’:’ ‘NR<2 {print $2}’
# ifconfig eth0|grep Bcast|awk -F’:’ ‘{print $2}’|awk ‘{print $1}’
# ifconfig eth0|grep Bcast|awk ‘{print $2}’|awk -F: ‘{print $2}’

以空格或冒号为分割符,+表示匹配前导字符出现一次或多次
[root@localhost shellDemo]# ifconfig ens33|awk -F’[ :]+’ 'NR2{print $3}’
192.168.169.129
# ifconfig eth0|awk NR2|awk -F ‘[ :]+’ ‘{print $4RS$6RS$8}’
# ifconfig eth0|awk -F"[ :]+" ‘/inet addr:/{print $4}’

awk的脚本编程

1、流程控制语句

if结构

格式:
awk 选项 '正则,地址定位{awk语句}'  文件名

{ if(表达式){语句1;语句2;.}}

[root@localhost shellDemo]# awk -F: '{if($3==0) {print KaTeX parse error: Expected 'EOF', got '}' at position 8: 1"是管理员"}̲}' 1.txt (id -u),不需要处理文件,直接在BEGIN里写就行
[root@localhost shellDemo]# awk ‘BEGIN{if($(id -u)==0){print “is admin”} }’
is admin

if…else结构:

格式:
{if(表达式){语句;语句;...}else{语句;语句;...}}

[root@localhost shellDemo]# awk -F: ‘{if($3==0){print $1" 是管理员"} else{print $1 " 不是管理员"} }’ 1.txt
root 是管理员
bin 不是管理员
daemon 不是管理员

if…elif…else结构:

格式:
{ if(表达式1){语句;语句;...}else if(表达式2){语句;语句;...}else if(表达式3){语句;语句;...}else{语句;语句;...}}

[root@localhost shellDemo]# awk -F: ‘{ if($30) {print $1,":是管理员"} else if($3>=1 && $3<=499 || $365534 ) {print $1,":是系统用户"} else {print $1,":是普通用户"}}’ 1.txt
root :是管理员
bin :是系统用户
daemon :是系统用户
adm :是系统用户
lp :是系统用户
sync :是系统用户
shutdown :是系统用户
halt :是系统用户
mail :是系统用户
operator :是系统用户
u5 :是普通用户
ntp :是系统用户
yunwei :是普通用户

2、循环语句
for循环

[root@localhost shellDemo]# awk 'BEGIN { for(i=1;i<=5;i++) {print i} }'
1
2
3
4
5
[root@localhost shellDemo]# awk 'BEGIN{sum=0;for(i=1;i<=5;i++) sum+=i;print sum}'
15

while循环

[root@localhost shellDemo]# awk 'BEGIN { i=1;while(i<=5) {print i;i++} }'
1
2
3
4
5
[root@localhost shellDemo]#  awk 'BEGIN{i=1;sum=0;while(i<=5) {sum+=i;i++}; print sum }'
15

嵌套循环

[root@localhost shellDemo]# awk 'BEGIN{ for(y=1;y<=5;y++) {for(x=1;x<=y;x++) {printf x} ;print } }'
1
12
123
1234
12345
[root@localhost shellDemo]# awk 'BEGIN{ y=1;while(y<=5) { for(x=1;x<=y;x++) {printf x};y++;print}}'
1
12
123
1234
12345

循环的控制:
break 条件满足的时候中断循环
continue 条件满足的时候跳过循环
# awk ‘BEGIN{for(i=1;i<=5;i++) {if(i3) break;print i} }’
1
2
# awk 'BEGIN{for(i=1;i<=5;i++){if(i3) continue;print i}}’
1
2
4
5

3、awk算数运算

+ - * / %() ^(幂2^3)

可以在模式中执行计算,awk都将按浮点数方式执行算术运算

[root@localhost shellDemo]# awk 'BEGIN{print 1+1}'
2
[root@localhost shellDemo]# awk 'BEGIN{print 1**1}'
1
[root@localhost shellDemo]# awk 'BEGIN{print 2**3}'
8
[root@localhost shellDemo]# awk 'BEGIN{print 2*3}'
6
[root@localhost shellDemo]# awk 'BEGIN{print 2/3}'
0.666667

awk统计案例

1、统计系统中各种类型的shell

#定义一个关联数组,然后遍历关联数组,先打印索引,在打印值
[root@localhost shellDemo]# awk -F: '{ shells[$NF]++ };END{for (i in shells) {print i,shells[i]} }' /etc/passwd
/bin/sync 1
/bin/bash 10
/sbin/nologin 16
/sbin/halt 1
/sbin/shutdown 1

2、统计网站访问状态

# ss -antp|grep 80|awk '{states[$1]++};END{for(i in states){print i,states[i]}}'
TIME_WAIT 578
ESTABLISHED 1
LISTEN 1

# ss -an |grep :80 |awk ‘{states[$2]++};END{for(i in states){print i,states[i]}}’
LISTEN 1
ESTAB 5
TIME-WAIT 25

# ss -an |grep :80 |awk ‘{states[$2]++};END{for(i in states){print i,states[i]}}’ |sort -k2 -rn
TIME-WAIT 18
ESTAB 8
LISTEN 1

3、统计访问网站的每个IP的数量

# netstat -ant |grep :80 |awk -F: '{ip_count[$8]++};END{for(i in ip_count){print i,ip_count[i]} }' |sort

# ss -an |grep :80 |awk -F":" ‘!/LISTEN/{ip_count[$(NF-1)]++};END{for(i in ip_count){print i,ip_count[i]}}’ |sort -k2 -rn |head

4、统计网站日志中PV量

统计Apache/Nginx日志中某一天的PV量  <统计日志>
# grep '27/Jul/2017' mysqladmin.cc-access_log |wc -l
14519

统计Apache/Nginx日志中某一天不同IP的访问量 <统计日志>
# grep ‘27/Jul/2017’ mysqladmin.cc-access_log |awk ‘{ips[$1]++};END{for(i in ips){print i,ips[i]} }’ |sort -k2 -rn |head

# grep ‘07/Aug/2017’ access.log |awk ‘{ips[$1]++};END{for(i in ips){print i,ips[i]} }’ |awk ‘$2>100’ |sort -k2 -rn

名词解释:

网站浏览量(PV)
名词:PV=PageView (网站浏览量)
说明:指页面的浏览次数,用以衡量网站用户访问的网页数量。多次打开同一页面则浏览量累计。用户每打开一个页面便记录1次PV。

名词:VV = Visit View(访问次数)
说明:从访客来到您网站到最终关闭网站的所有页面离开,计为1次访问。若访客连续30分钟没有新开和刷新页面,或者访客关闭了浏览器,则被计算为本次访问结束。

独立访客(UV)
名词:UV= Unique Visitor(独立访客数)
说明:1天内相同的访客多次访问您的网站只计算1个UV。

独立IP(IP)
名词:IP=独立IP数
说明:指1天内使用不同IP地址的用户访问网站的数量。同一IP无论访问了几个页面,独立IP数均为1

1. 任务/背景

web服务器集群中总共有9台机器,上面部署的是Apache服务。由于业务不断增长,每天每台机器上都会产生大量的访问日志,现需要将每台web服务器上的apache访问日志保留最近3天的,3天以前的日志转储到一台专门的日志服务器上,已做后续分析。如何实现每台服务器上只保留3天以内的日志?

2. 具体要求

  1. 每台web服务器的日志对应日志服务器相应的目录里。如:web1——>web1.log(在日志服务器上)
  2. 每台web服务器上保留最近3天的访问日志,3天以前的日志每天凌晨5:03分转储到日志服务器
  3. 如果脚本转储失败,运维人员需要通过跳板机的菜单选择手动清理日志

3. 涉及知识点

  1. shell的基本语法结构
  2. 文件同步rsync
  3. 文件查找命令find
  4. 计划任务crontab
  5. apache日志切割
  6. 其他

你可能感兴趣的:(shell,运维)