grep / sed / awk 入门

grep

  • -E:相当于 egrep,支持扩展正则。
  • -A:匹配过滤的内容以及下面的行,例如下面5行为-A5
  • -B:匹配过滤的内容以及上面的行,例如上面5行为-B5
  • -C:匹配过滤的内容以及上下的行,例如上下5行为-C5
  • -c:统计出现了多少行,类似wc -l
  • -v:显示除过滤行以外的其他行内容。
  • -n:显示行号。
  • -i:忽略大小写。
  • -w:精确过滤。

精确过滤的几种方法(只匹配 abc):

echo abc abcde abcdef abcc | grep -w abc
echo abc abcde abcdef abcc | grep '\babc\b'
echo abc abcde abcdef abcc | grep '\<abc\>'

sed

查找

  • '1p' '2p':指定行号进行查找。
  • '1,5p':指定行号范围进行查找。
  • /word/p:类似于 grep 过滤,支持正则,扩展正则需加上-r参数。
  • /10:00/,/11:00/p:按照指定范围进行过滤。如果查找不到结束关键字,则输出到最后一行。

注意:使用时需加上-n参数,否则 sed 默认输出所有内容。

# 查找第5行内容
sed -n '5p' 2_test.txt

# 查找第5-9行内容
sed -n '5,9p' 2_test.txt
# 查找从第5行开始到最后一行
sed -n '5,$p' 2_test.txt
# 查找最后一行内容
sed -n '$p' 2_test.txt

# 查找含有 demo 的行
sed -n '/demo/p' 2_test.txt
# 支持正则查找
sed -n '/[ab]/p' 2_test.txt
sed -nr '/s?t$/p' 2_test.txt

# 范围
sed -nr '/apple/,/demo/p' 2_test.txt

删除

  • '1d':指定行号进行删除。
  • '1,5d':指定行号范围进行删除。
  • /word/d:类似于 grep 过滤,支持正则,扩展正则需加上-r参数。
  • /10:00/,/11:00/d:按照指定范围进行删除。
# 删除第2-5行内容
$ sed '2,5d' 2_test.txt
1 apple
6 demo
7 test
8 hhst
9
10

# 支持正则表达式
$ sed -r '/t$/d' 2_test.txt 
1 apple
2 apple
4 amazon
5 twitter
6 demo
9
10

增加

  • c:替换指定行内容。
  • a:append,追加,向指定的行或每一行追加内容(行后面)。
  • i:insert,插入,向指定的行或每一行插入内容(行前面)。
# 行后增加
$ sed '3a insert content' 2_test.txt 
1 apple
2 apple
3 microsoft
insert content
4 amazon

# 行前增加
$ sed '3i insert content' 2_test.txt 
1 apple
2 apple
insert content
3 microsoft
4 amazon

# 替换
$ sed '3c insert content' 2_test.txt 
1 apple
2 apple
insert content
4 amazon

替换

s:substitute 替换,sed默认只替换每行第一个匹配的内容。
g:global 全局替换,替换每行所有的匹配内容。
使用方法:s###gs///g[email protected]@@g

# 待处理文本内容
$ cat 2_test.txt 
01 apple
02 apple
03 microsoft
04 amazon
05 twitter
06 demo
07 test
08 hhst
09
10

# 将数字替换为空
$ sed 's#[0-9]##g' 2_test.txt 
 apple
 apple
 microsoft
 amazon
 twitter
 demo

# 不加 g 的情况
$ sed 's#[0-9]##' 2_test.txt
1 apple
2 apple
3 microsoft
4 amazon
5 twitter
6 demo
7 test
8 hhst
9
0

后项引用,反向引用。

# 给 123 头尾加上尖括号,\1 表示第一对小括号
$ echo '123' | sed -r 's#(.*)#<\1>#g'
<123>

# 交换下划线前后的内容
$ echo 'hello_world' | sed -r 's#(^.*)_(.*$)#\2_\1#g'
world_hello

实例:过滤 IP 地址

# 未过滤
$ ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.166.161  netmask 255.255.255.0  broadcast 172.16.166.255

# 通过 sed 过滤
$ ifconfig ens33 | sed -n '2p' | sed -r 's#^.*inet (.*)  net.*$#\1#g'
172.16.166.161

# 简化
$ ifconfig ens33 | sed -nr '2s#^.*inet (.*)  net.*$#\1#gp'
172.16.166.161

实例:过滤权限

# 未过滤
$ stat 2_test.txt 
  文件:2_test.txt
  大小:82              块:8          IO 块:4096   普通文件
设备:10302h/66306d     Inode:396927      硬链接:1
权限:(0664/-rw-rw-r--)  Uid:( 1000/suzukaze)   Gid:( 1000/suzukaze)

# 过滤后
$ stat 2_test.txt | sed -nr '4s#^.*\(0(.*)/-.*$#\1#gp'
664

# 一个小坑,在过滤之前先查看该命令自身是否有提供过滤选项,别急着正则过滤处理
$ stat -c%a 2_test.txt
664

awk

内置变量、参数

  • NR:Number of Record 记录号(行号)
  • NF:Number of Fields 每行的字段数(列数)
  • -v FS:Field Separator 字段分隔符,相当于-F
  • -v OFS:Output Field Separator 输出字段分隔符

  • NR==1:取出指定行。
  • NR>=1 && NR<=5:取出指定范围行。
  • /word/:取出包含关键字的行。
  • /word1/,/word2/:取出包含关键字范围的行。如果查找不到结束关键字,则输出到最后一行。
$ awk 'NR==5' 2_test.txt 
05 twitter

$ awk '/ap/,/tes/' 2_test.txt 
01 apple
02 apple
03 microsoft
04 amazon
05 twitter
06 demo
07 test

使用-F指定分隔符,默认为空格(包括连续的空格和tab)。

  • $n:取出第n列(n>0)。
  • $0:取出整行内容。
  • $NF:取出最后一列。
# 取出第5列和第8列
$ ll | awk '{print $5,$8}'
4096 14:07
4096 19:40
95 19:03
82 14:07
4096 19:14
4096 19:14

# column -t 有对齐效果
$ ll | awk '{print $5,$8}' | column -t
4096    14:07
4096    19:40
95      19:03
82      14:07
4096    19:14
4096    19:14

# 从文件中取列,指定冒号为分隔符 
$ awk -F: '{print $1,$NF}' /etc/passwd
root /bin/bash
daemon /usr/sbin/nologin
bin /usr/sbin/nologin
sys /usr/sbin/nologin
sync /bin/sync
games /usr/sbin/nologin
man /usr/sbin/nologin

# 使用双引号自定义内容
$ awk -F: '{print $1"---"$NF}' /etc/passwd
root---/bin/bash
daemon---/usr/sbin/nologin
bin---/usr/sbin/nologin

# 自定义分隔符,-vOFS == -v OFS
$ awk -F: -vOFS=: '{print $1,$NF}' /etc/passwd
root:/bin/bash
daemon:/usr/sbin/nologin
bin:/usr/sbin/nologin
sys:/usr/sbin/nologin

实例:过滤 IP 地址

# 过滤前
$ ip address show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:99:ea:24 brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 172.16.166.161/24 brd 172.16.166.255 scope global dynamic noprefixroute ens33
       valid_lft 1044sec preferred_lft 1044sec
    inet6 fe80::abe6:a1ef:a294:b07d/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

# 过滤后,分隔符可以使用正则表达式
$ ip a s ens33 | awk -F"[ /]+" 'NR==4{print $3}'
172.16.166.161

模式匹配

格式:pattern {action}

A pattern can be:
            BEGIN
            END
            expression
            expression , expression

正则

  • ~:匹配。
  • !~:不匹配。
# 第3列以2开头的行
$ awk -F: '$3~/^2/' /etc/passwd
bin:x:2:2:bin:/bin:/usr/sbin/nologin

# 第3列以2开头,打印第1列和最后1列
$ awk -F: '$3~/^2/{print $1,$NF}' /etc/passwd
bin /usr/sbin/nologin

范围

  • //,//
  • NR==1,NR==5
$ awk -F: '/120/,/200/{print $1}' /etc/passwd
nm-openvpn
saned
colord
geoclue
pulse

特殊模式

  • BEGIN:在awk读取文件之前执行。
  • END:在awk读取文件之后执行。
# 统计空行,效果类似 wc -l
$ awk '/^$/{i++}END{print i}' /etc/services
6

# 从1累加到100
$ seq 100 | awk '{sum=sum+$1}END{print sum}'
5050

# 使用分号隔开多个表达式
$ seq 5 | awk '{sum=sum+$1; print sum}END{print "total",sum}'
1
3
6
10
15
total 15

数组

  • 赋值:array[0]="hello",字符串需要使用双引号,否则 awk 会识别为变量,数字可以不用添加双引号。
  • 循环:for(i in array),此处的i为下标。
# 赋值
$ awk 'BEGIN{list[0]="hello";list[1]="awk";list[2]=123;print list[0],list[1],list[2]}'
hello awk 123

# 循环输出
$ awk 'BEGIN{list[0]="awk"; list[1]="hey"; list[2]=123; for(i in list)print i,list[i]}'
2 123
0 awk
1 hey

实例:统计域名出现次数

# 文件内容如下 
https://www.apple.com/1.html
https://api.apple.com/2.html
https://api.apple.com/index.html
https://www.apple.com/12.html
https://download.apple.com/index.html
https://www.apple.com/iphone.html

# 统计结果
$ awk -F"[./]+" '{array[$2]++}END{for(i in array)print i,array[i]}' 03_url.txt 
api 2
www 3
download 1

# 排序
$ awk -F"[./]+" '{array[$2]++}END{for(i in array)print i,array[i]}' 03_url.txt | sort -rnk2
www 3
api 2
download 1

for 循环

见例子:

# 计算1-100累加
$ awk 'BEGIN{for(i=1;i<=100;i++)sum+=i; print sum}'
5050

if 判断

见例子:

# 打印磁盘使用率大于1%的挂载点
$ df -h | awk -F"[ %]+" 'NR>1{if($5>1)print $6,"disk is not enough"}'
/ disk is not enough
/boot/efi disk is not enough
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
颜文字
上一篇
下一篇