1.Linux三剑客之sed命令
1.1sed简介
sed之所以能以行为单位的编辑或修改文本,其原因在于它使用了两个空间:一个是活动的
“模式空间(pattern space)”
,另一个是起辅助作用的“保持空间(hold space)
这2个空间的使用。
模式空间:
可以想成工程里面的流水线,数据之间在它上面进行处理。
保持空间:
可以想象成仓库,我们在进行数据处理的时候,作为数据的暂存区域。
正常情况下,如果不显示使用某些高级命令,保持空间不会使用到!
sed在正常情况下,将处理的行读入模式空间,脚本中的“sed command(sed命令)”就一条接着一条进行处理,直到脚本执行完毕。然后该行被输出,模式被清空;接着,在重复执行刚才的动作,文件中的新的一行被读入,直到文件处理完毕。
sed 工作原理:
一般情况下,数据的处理只使用模式空间(pattern space),按照如上的逻辑即可完成主要任务。但是某些时候,通过使用保持空间(hold space),还可以带来意想不到的效果。
- 使用方法
sed [option] [command] [file]
1.2sed模式空间的常用命令
sed模式空间的常用命令有
N:通过读取新的输入行,并将它添加到模式空间里面原有的内容之后,创建多行模式空间
g:把保持空间里面的内容复制到模式空间,但是它会覆盖原有的内容
G:把保持空间里面的内容追加到模式空间,但是它是在原有的内容之后追加
h:把模式空间里面的内容复制到保持空间,但是它会覆盖原有的内容
H:把模式空间里面的内容追加到保持空间,但是它是在原有的内容之后追加
d:删除模式空间里面的内容,并且它会自动进入下一个循坏
D:删除多行模式空间里面的内容,但是它不会读取下一行,相反它会返回脚本的顶端,将这些指令应用于模式空间剩余的内容
x:交换保持空间和模式空间里面的内容
- 使用方法
1.3案例
N 命令会将下一行文本内容添加到缓冲区已有数据之后(之间用换行符分隔),从而使前后两个文本行同时位于缓冲区中,sed 命令会将这两行数据当成一行来处理
[root@localhost ~]# cat test
one two three
tom ppp zj
zz hh xx
[root@localhost ~]# sed '/zj/{N;s/\n/ /}' test
one two three
tom ppp zj zz hh xx
[root@localhost ~]#
D命令原理:当遇到两个空行,只删除第一个空行。当一个空行后面跟有文本,模式空间可以正常输出
[root@localhost ~]# cat abc
one two three
test redhat next
tom jerry jake
123 310 ABC
[root@localhost ~]# sed '
> /^$/{
> N
> /^\n$/D
> } ' test
sed: can't read test: No such file or directory
[root@localhost ~]# sed '
/^$/{
N
/^\n$/D
} ' abc
one two three
test redhat next
tom jerry jake
123 310 ABC
[root@localhost ~]#
h 将模式空间的内容拷贝到保持空间,原来模式空间里的内容清除
H 将模式空间的内容拷贝到保持空间\n后
g 将保持空间内容拷贝到模式空间,原来的模式空间里的内容清除
G 将保持空间的内容复制到模式空间\n后
# 将one这一行内容放入保持空间,然后覆盖掉模式空间的test这一行
[root@localhost ~]# sed '/one/h;/test/g' test
one two three
one two three
tom jerry jake
123 310 ABC
# 将one这一行放入到保持空间,然后追加到test行后
[root@localhost ~]# sed '/one/h;/test/G' test
one two three
test redhat next
one two three
tom jerry jake
123 310 ABC
# 将1这一行放入保持空间后删除,追加到模式空间中
[root@localhost ~]# cat test
11
22
111
222
[root@localhost ~]# sed '/1/{h;d};/2/G' test
22
11
222
111
x 交换保持空间和模式空间里面的内容
[root@localhost ~]# cat test
1
2
3
4
5
# 匹配2到保持空间然后删除模式空间内容,匹配3到保持空间然后交换保持空间和模式空间的内容
[root@localhost ~]# sed '
/2/{
h
d
}
/3/{
x
}
' test
1
2
4
5
b 在脚本中将控制转移到另一行
[root@localhost ~]# cat test
hello china
hello world
hello china world
#匹配china,继续匹配hello world,当不匹配其中一个时,进入下一个命令
[root@localhost ~]# cat txt
:top
/china/{
/hello world/b top
s/china/CHINA/
}
[root@localhost ~]# sed -f txt test
hello CHINA
hello world
hello CHINA world
#匹配hell,继续匹配hell world,当匹配正确时调转回top
[root@localhost ~]# cat txt
:top
/hello/{
/hello world/b top
s/china/CHINA/
}
[root@localhost ~]# sed -f txt test
hello CHINA
2.Linux三剑客之awk命令
- awk简介
awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
awk 是一种很棒的语言,它适合文本处理和报表生成,其语法较为常见,借鉴了某些语言的一些精华,如 C 语言等。在 linux 系统日常处理工作中,发挥很重要的作用,掌握了 awk将会使你的工作变的高大上。 awk 是三剑客的老大,利剑出鞘,必会不同凡响。
- 使用方法
awk '{pattern + action}' {filenames}
尽管操作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 pattern就是要表示的正则表达式,用斜杠括起来。
awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。
通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。
- awk的原理
通过一个简短的命令,我们来了解其工作原理。
[root@localhost ~]# awk '{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
.....................................................
[root@localhost ~]# echo hhh|awk '{print "hi"}'
hi
[root@localhost ~]# awk '{print "xixi"}' /etc/passwd
xixi
xixi
.....................................................
你将会见到/etc/passwd 文件的内容出现在眼前。现在,解释 awk 做了些什么。调用 awk时,我们指定/etc/passwd 作为输入文件。执行 awk 时,它依次对/etc/passwd 中的每一行执行 print 命令。
所有输出都发送到 stdout,所得到的结果与执行 cat /etc/passwd 完全相同。
现在,解释{ print }代码块。在 awk 中,花括号用于将几块代码组合到一起,这一点类似于 C 语言。在代码块中只有一条 print 命令。在 awk 中,如果只出现 print 命令,那么将打印当前行的全部内容。
再次说明, awk 对输入文件中的每一行都执行这个脚本。
$ awk -F":" '{ print $1 }' /etc/passwd
$ awk -F":" '{ print $1 $3 }' /etc/passwd
$ awk -F":" '{ print $1 " " $3 }' /etc/passwd
$ awk -F":" '{ print "username: " $1 "\t\tuid:" $3" }' /etc/passwd
-F参数:指定分隔符,可指定一个或多个
print 后面做字符串的拼接`
示例:
[root@localhost ~]# cat abc
tom zhang 111-222-33
[root@localhost ~]# awk -F'g' '{print $1}' abc
tom zhan
[root@localhost ~]# awk -F'zhang' '{print $1}' abc
tom
[root@localhost ~]# awk -F'zhang' '{print $2}' abc
111-222-33
[root@localhost ~]#
//利用awk命令获取本机IP
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:fb:6a:38 brd ff:ff:ff:ff:ff:ff
inet 192.168.8.129/24 brd 192.168.8.255 scope global dynamic noprefixroute ens160
valid_lft 1319sec preferred_lft 1319sec
inet6 fe80::bd2e:835:10b3:c30/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:61:67:63 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel master virbr0 state DOWN group default qlen 1000
link/ether 52:54:00:61:67:63 brd ff:ff:ff:ff:ff:ff
[root@localhost ~]# ip a|grep 'inet '|grep -v '127.0.0.1'
inet 192.168.8.129/24 brd 192.168.8.255 scope global dynamic noprefixroute ens160
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
[root@localhost ~]# ip a|grep 'inet '|grep -v '127.0.0.1'|awk -F'[ /]+' '{print $3}'
192.168.8.129
192.168.122.1
[root@localhost ~]# ip a|grep 'inet '|grep -v '127.0.0.1'|grep -v '192.168.122.1'|awk -F'[ /]+' '{print $3}'
192.168.8.129
[root@localhost ~]#
//获取根分区的大小
[root@localhost ~]# df -h
文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 3.8G 4.0K 3.8G 1% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 3.9G 9.7M 3.8G 1% /run
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/mapper/rhel-root 50G 7.8G 43G 16% /
/dev/mapper/rhel-home 142G 1.1G 141G 1% /home
/dev/nvme0n1p1 1014M 229M 786M 23% /boot
tmpfs 779M 1.2M 778M 1% /run/user/42
tmpfs 779M 4.0K 779M 1% /run/user/0
[root@localhost ~]# df -h|awk '/root/{print $4}' //匹配root关键字,打印第四列
43G
[root@localhost ~]# df -h|awk 'NR==6{print $4}' //匹配第六行,打印第四列
43G
[root@localhost ~]#
字段和引用的分离
awk允许使用字段操作符$来指定字段。在该操作符后面跟着一个数字或流量用于标识字段的位置。
[root@localhost ~]# echo "tom zhang 111-222-3333"
tom zhang 111-222-3333
[root@localhost ~]# echo "tom zhang 111-222-3333"|awk '{print $2,$1,$3}'
zhang tom 111-222-3333
[root@localhost ~]#
可以用任何计算值为整数的表达式来表示一个字段,而不只是用数字和变量
[root@localhost ~]# awk 'BEGIN{print 1+2}'
3
[root@localhost ~]# awk 'BEGIN{print 1/2}'
0.5
[root@localhost ~]# awk 'BEGIN{print 1*2}'
2
[root@localhost ~]# awk 'BEGIN{print 2-1}'
1
[root@localhost ~]#
下面通过几实例来了解下awk的工作原理:
实例一:只查看test.txt文件(100行)内第10到第15行的内容(企业面试)
[root@localhost ~]# awk '{if(NR>=10 && NR<=30) print $1}' test.txt
10
11
12
13
14
15
实例二:已知test.txt文件内容为:
[root@localhost ~]# cat test.txt
I am pengyudong,my qq is 336786531
[root@localhost ~]#
请从该文件中过滤出'pengyudong'字符串与336786531最后输出的结果为:pengyudong 336786531
[root@localhost ~]# cat test.txt
I am pengyudong,my qq is 336786531
[root@localhost ~]# awk -F '[ ,]+' '{print $3" "$7}' test.txt
pengyudong 336786531
[root@localhost ~]#
- BEGIN 和 END 模块
通常,对于每个输入行, awk 都会执行每个脚本代码块一次。然而,在许多编程情况中,可能需要在 awk 开始处理输入文件中的文本之前执行初始化代码。对于这种情况, awk 允许您定义一个 BEGIN 块。
因为 awk 在开始处理输入文件之前会执行 BEGIN 块,因此它是初始化 FS(字段分隔符)变量、打印页眉或初始化其它在程序中以后会引用的全局变量的极佳位置。
awk 还提供了另一个特殊块,叫作 END 块。 awk 在处理了输入文件中的所有行之后执行这个块。通常, END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。
实例一:统计/etc/passwd的账户人数
[root@localhost ~]# awk '{count++;print $0;} END{print "user count is ",count}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
......
user count is 48
[root@localhost ~]#
实例二:统计某个文件夹下的文件占用的字节数
[root@localhost ~]# ll |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ",size}'
[end]size is 3250
[root@localhost ~]#
- awk运算符
awk 赋值运算符:a+5;等价于: a=a+5;其他同类
[root@localhost ~]# awk 'BEGIN{a=5;a+=5;print a}'
10
[root@localhost ~]#
awk逻辑运算符:
[root@localhost ~]# awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'
0 1
[root@localhost ~]#
- 常用awk内置变量
注:内置变量很多,参阅相关资料
字段分隔符 FS
FS="[" “:]+” 以一个或多个空格或:分隔
[root@localhost ~]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# awk -F [" ":]+ '{print $1,$2,$3}' hello.txt
root x 0
字段数量 NF
[root@localhost ~]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin:888
[root@Gin scripts]# awk -F ":" 'NF==8{print $0}' hello.txt
bin:x:1:1:bin:/bin:/sbin/nologin:888
记录数量 NR
[root@localhost ~]# ifconfig ens160|awk -F [" ":]+ 'NR==2{print $3}'
192.168.8.130
[root@localhost ~]#
[root@localhost ~]# cat test
香飘飘
优乐美
阿萨姆
雀巢
[root@localhost ~]# awk '{print NR "."$0}' test
1.香飘飘
2.优乐美
3.阿萨姆
4.雀巢
[root@localhost ~]# cat test.sh
#!/bin/bash
echo "商品列表:"
awk '{print NR".",$0}' test
read -p "请输入商品序号:" choose
awk -vchoice=$choose 'NR==choice{print $0}' test
[root@localhost ~]# bash test.sh
商品列表:
1. 香飘飘
2. 优乐美
3. 阿萨姆
4. 雀巢
请输入商品序号:2
优乐美
[root@localhost ~]#