grep

  • 作用:过滤文本内容 | 选项 | 描述 | | —- | —- | | -E:—extendedd—regexp | 扩展正则表达式ERE | | -i:—ignore—case | 忽略大小写 | | -n:—line—number | 打印行号 | | -o:—only—matching | 只打印匹配的内容 | | -c:—count | 只打印每个文件匹配的行数 | | -B:—before—context=NUM | 打印匹配的前几行 | | -A:—after-context=NUM | 打印匹配的后几行 | | -C:—context=NUM | 打印匹配的前后几行 | | —color[=WHEN] | 匹配的字体颜色,别名已经定义了 | | -v:—invert—match | 打印不匹配的行 | | -e | 多点操作eg:grep -e “^s” -e “s$” |

实例

  • 样本文件内容 ```bash [root@server1 ~]# cat test1 asdkahsduoa aslkdsl oiofr sdjo A F aSDD CASDC

asdo ca

  1. <a name="Xzem7"></a>
  2. ### 实例1: -i选项
  3. 打印出所有的a无论大小写
  4. ```bash
  5. [root@server1 ~]# grep -i 'a' test1
  6. asdkahsduoa
  7. aslkdsl
  8. A
  9. aSDD
  10. CASDC
  11. asdo
  12. ca

实例2: -n选项

打印出所有的a无论大小写,并且显示该字符串所在的行

  1. [root@server1 ~]# grep -in 'a' test1
  2. 1:asdkahsduoa
  3. 2:aslkdsl
  4. 5:A
  5. 7:aSDD
  6. 8:CASDC
  7. 10:asdo
  8. 11:ca

实例3:-o选项

仅仅打印出所有匹配的字符串

  1. [root@server1 ~]# grep -io 'a' test1
  2. a
  3. a
  4. a
  5. a
  6. A
  7. a
  8. A
  9. a
  10. a

实例4:-c选项

打印出匹配的字符串有多少行

  1. [root@server1 ~]# grep -ic 'a' test1
  2. 7

这里只显示7,没有算上大写A,-c参数使-i参数失效。

实例5:-B

打印出字符S前面两行

  1. [root@server1 ~]# grep -B 2 'S' test1
  2. A
  3. F
  4. aSDD
  5. CASDC

实例6:-A

打印出字符S后面两行

  1. [root@server1 ~]# grep -A 2 'S' test1
  2. aSDD
  3. CASDC
  4. asdo

实例7:-C

打印出字符S前后两行

  1. [root@server1 ~]# grep -C 2 'S' test1
  2. A
  3. F
  4. aSDD
  5. CASDC
  6. asdo

实例8:取反 -v

打印出不包含大小写s的所有行

  1. [root@server1 ~]# grep -iv 'S' test1
  2. oiofr
  3. A
  4. F
  5. ca

用法

grep可以直接从文件当中搜索某个关键词,也可以从标准输入里面搜索

  1. [root@server1 ~]# grep root /etc/passwd
  2. root:x:0:0:root:/root:/bin/bash
  3. operator:x:11:0:operator:/root:/sbin/nologin
  4. [root@server1 ~]# cat /etc/passwd | grep 'root'
  5. root:x:0:0:root:/root:/bin/bash
  6. operator:x:11:0:operator:/root:/sbin/nologin

正则表达式(基于grep)

正则表达式是为了处理大量文本或者字符串而定义的一套规则,通过定义特殊的符号辅助,系统管理员可以快速过滤、输出或替换需要的字符串。
Linux正则表达式一般以行为单位。

基础正则表达式

符号 描述
. 可以匹配任意单个字符(必须存在)
^ 匹配以某个字符开头的行
$ 匹配以某个字符结尾的行
* 匹配前面一个字符出现0次或多次;a*b
.* 表示任意长度的任意字符
[] 表示匹配括号内的一个字符
[^] 匹配[^字符]之外的任意一个字符
< 锚定单词首部;<root
> 锚定单词尾部
{m,n} 表示前面的字符至少出现m次,至多出现n次
() 表示对某个单词进行分组,\1表示第一个分组进行调用

扩展正则

  • egrep …
  • grep -E …
  • 扩展正则支持所有基础正则
  • 扩展正则中{}和[]不用转义符号可以直接使用 | 符号 | 描述 | | —- | —- | | + | 表示前面的字符至少出现一次的情况 | | | | 表示或 | | ? | 表示前面的字符至多出现一次的情况 |

常用情景

查看配置文件时去除所有注释和空行

  1. [root@server1 ~]# grep -Ev '^#|^$' /etc/ssh/sshd_config

sed

sed命令是利用script来处理文本文件,sed可依照script的指令,来处理、编辑文本文件。
sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等等。

语法

  1. sed [-hnV][-e<script>][-f<script文件>][文本文件]

参数说明

-e<script>--expression=<script>,以选项中指定的script来处理输入的文本文件,这里的script是直接写在命令行里的。
-f<script文件名>--filename=<script文件名>,以选项中指定的script文件来处理输入的文本文件。
-h或—help显示帮助
-n--quiet--silent,仅显示script处理后的结果。
-v--version,显示版本信息。

动作说明

a :新增, a 的后面可以接字符串,而这些字符串会在新的一行出现(目前的下一行)~
c :取代, c 的后面可以接字符串,这些字符串可以取代 n1,n2 之间的行(用于整行替换)!
d :删除,因为是删除,所以 d 后面通常不接任何字符串;
i :插入, i 的后面可以接字符串,而这些字符串会在新的一行出现(目前的上一行);
p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行
s :取代,可以直接进行取代的工作!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g (用于行内替换

实例

  • 准备测试文件
    1. [root@server1 ~]# cat test
    2. line one
    3. line two
    4. line three
    5. line four
    6. line five
    在test文件第四行后添加一行,并将结果输出到标准输出
    1. [root@server1 ~]# sed -e 4a\newline test
    2. line one
    3. line two
    4. line three
    5. line four
    6. newline
    7. line five

    以行为单位的新增/删除

  1. 将 /etc/passwd 的内容列出并且列印行号,同时,请将第 2~5 行删除

    1. [root@localhost ~]# nl /etc/passwd | sed '2,5d'
    2. 1 root:x:0:0:root:/root:/bin/bash
    3. 6 sync:x:5:0:sync:/sbin:/bin/sync
    4. 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    5. 8 halt:x:7:0:halt:/sbin:/sbin/halt
    6. 9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    7. 10 operator:x:11:0:operator:/root:/sbin/nologin

    sed 的动作为 ‘2,5d’ ,那个 d 就是删除!因为 2-5 行给他删除了,所以显示的数据就没有 2-5 行。 另外,注意一下,原本应该是要下达 sed -e 才对,没有 -e 也行!同时也要注意的是, 如果 sed 后面直接接的动作,请务必以 ‘’ 两个单引号括住

  2. 只要删除第2行

    1. root@localhost ~]# nl /etc/passwd | sed '2d'
    2. 1 root:x:0:0:root:/root:/bin/bash
    3. 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4. 4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    5. 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    6. 6 sync:x:5:0:sync:/sbin:/bin/sync
    7. 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    8. 8 halt:x:7:0:halt:/sbin:/sbin/halt
    9. 9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    10. 10 operator:x:11:0:operator:/root:/sbin/nologin
  3. 删除第3到最后一行

    1. [root@localhost ~]# nl /etc/passwd | sed '3,$d'
    2. 1 root:x:0:0:root:/root:/bin/bash
    3. 2 bin:x:1:1:bin:/bin:/sbin/nologin
  4. 在第二行后(即第三行)加入一行“hello world”

    1. [root@localhost ~]# nl /etc/passwd | sed '2a hello world'
    2. 1 root:x:0:0:root:/root:/bin/bash
    3. 2 bin:x:1:1:bin:/bin:/sbin/nologin
    4. hello world
    5. 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    6. 4 adm:x:3:4:adm:/var/adm:/sbin/nologin
  5. 加在第二行前面

    1. [root@localhost ~]# nl /etc/passwd | sed '2i hello world'
    2. 1 root:x:0:0:root:/root:/bin/bash
    3. hello world
    4. 2 bin:x:1:1:bin:/bin:/sbin/nologin
    5. 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
  6. 增加多行文字

    1. [root@localhost ~]# nl /etc/passwd | sed '2a hello world\> nihao'
    2. 1 root:x:0:0:root:/root:/bin/bash
    3. 2 bin:x:1:1:bin:/bin:/sbin/nologin
    4. hello world
    5. nihao
    6. 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    7. 4 adm:x:3:4:adm:/var/adm:/sbin/nologin

    以行为单位替换/显示

    将第2-5行的内容取代成为『No 2-5 number』

    1. [root@localhost ~]# nl /etc/passwd | sed '2,5c No 2-5 number'
    2. 1 root:x:0:0:root:/root:/bin/bash
    3. No 2-5 number
    4. 6 sync:x:5:0:sync:/sbin:/bin/sync
    5. 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

    仅列出 /etc/passwd 文件内的第 5-7 行

    1. [root@localhost ~]# nl /etc/passwd | sed -n '5,7p'
    2. 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    3. 6 sync:x:5:0:sync:/sbin:/bin/sync
    4. 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

    数据的搜寻与显示

    搜索 /etc/passwd有root关键字的行

    1. [root@localhost ~]# nl /etc/passwd | sed -n '/root/p'
    2. 1 root:x:0:0:root:/root:/bin/bash
    3. 10 operator:x:11:0:operator:/root:/sbin/nologin

    数据的搜寻与删除

    删除/etc/passwd所有包含root的行,其他行输出

    1. [root@localhost ~]# nl /etc/passwd | sed '/root/d'
    2. 2 bin:x:1:1:bin:/bin:/sbin/nologin
    3. 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4. 4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    5. 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    6. 6 sync:x:5:0:sync:/sbin:/bin/sync
    7. 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    8. 8 halt:x:7:0:halt:/sbin:/sbin/halt
    9. 9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    10. 11 games:x:12:100:games:/usr/games:/sbin/nologin
    11. 12 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    12. 13 nobody:x:99:99:Nobody:/:/sbin/nologin
    13. 14 systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
    14. 15 dbus:x:81:81:System message bus:/:/sbin/nologin
    15. 16 polkitd:x:999:998:User for polkitd:/:/sbin/nologin
    16. 17 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    17. 18 postfix:x:89:89::/var/spool/postfix:/sbin/nologin

    数据的搜寻并执行命令

    搜索/etc/passwd,找到root对应的行,执行后面花括号中的一组命令,每个命令之间用分号分隔,这里把bash替换为blueshell,再输出这行。

    1. [root@localhost ~]# nl /etc/passwd | sed -n '/root/{s/bash/blueshell/;p;q}'
    2. 1 root:x:0:0:root:/root:/bin/blueshell

    最后的q是退出,不然会继续找下去。

    数据的搜寻并替换

    除了整行的处理模式之外, sed 还可以用行为单位进行部分数据的搜寻并取代

    1. sed 's/要被取代的字串/新的字串/g'

    查询IP
    原始信息

    1. [root@localhost ~]# ifconfig
    2. ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    3. inet 192.168.91.128 netmask 255.255.255.0 broadcast 192.168.91.255
    4. inet6 fe80::2de4:b37a:36e9:ae2e prefixlen 64 scopeid 0x20<link>
    5. ether 00:0c:29:d3:76:83 txqueuelen 1000 (Ethernet)
    6. RX packets 33461 bytes 32133707 (30.6 MiB)
    7. RX errors 0 dropped 0 overruns 0 frame 0
    8. TX packets 11322 bytes 1300148 (1.2 MiB)
    9. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    10. lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    11. inet 127.0.0.1 netmask 255.0.0.0
    12. inet6 ::1 prefixlen 128 scopeid 0x10<host>
    13. loop txqueuelen 1000 (Local Loopback)
    14. RX packets 10 bytes 697 (697.0 B)
    15. RX errors 0 dropped 0 overruns 0 frame 0
    16. TX packets 10 bytes 697 (697.0 B)
    17. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    取有IP地址那一行

    1. [root@localhost ~]# ifconfig | sed -n '/netmask/p'
    2. inet 192.168.91.128 netmask 255.255.255.0 broadcast 192.168.91.255
    3. inet 127.0.0.1 netmask 255.0.0.0

    删除IP地址前面和后面的东西

    1. [root@localhost ~]# ifconfig | sed -n '/netmask/p' | sed 's/^.*inet //g' | sed 's/netmask.*$//g'
    2. 192.168.91.128
    3. 127.0.0.1

    取第一行

    1. [root@localhost ~]# ifconfig | sed -n '/netmask/p' | sed 's/^.*inet //g' |
    2. sed 's/ netmask.*$//g' | sed -n '1p'
    3. 192.168.91.128

    ps:可以在末尾加g替换每一个匹配的关键字,否则只替换每行的第一个

    多点编辑

    一条sed命令,删除/etc/passwd第三行到末尾的数据,并把bash替换为blueshell

    1. [root@localhost ~]# nl /etc/passwd | sed -e '3,$d' -e 's/bash/blueshell/'
    2. 1 root:x:0:0:root:/root:/bin/blueshell
    3. 2 bin:x:1:1:bin:/bin:/sbin/nologin

    -e表示多点编辑,第一个编辑命令删除/etc/passwd第三行到末尾的数据,第二条命令搜索bash替换为blueshell。

    直接修改文件内容(危险动作)

    1. [root@localhost ~]# cat test
    2. line one.
    3. line two.
    4. line three.
    5. line four.
    6. line five.
    1. [root@localhost ~]# sed -i 's/\.$/\!/g' test
    2. [root@localhost ~]# cat test
    3. line one!
    4. line two!
    5. line three!
    6. line four!
    7. line five!

    利用sed在最后一行添加“# test”

    1. [root@localhost ~]# sed -i '$a # test' test
    2. [root@localhost ~]# cat test
    3. line one!
    4. line two!
    5. line three!
    6. line four!
    7. line five!
    8. # test

    awk

    使用方法

    1. awk '{pattern + action}' {filenames}

    其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号{}不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 pattern就是要表示的正则表达式,用斜杠括起来。

awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。

通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。

awk原理

  1. [root@localhost ~]# awk '{print $0}' /etc/passwd

执行 awk 时,它依次对/etc/passwd 中的每一行执行 print 命令。
image.png

“$0”是一条记录,”$n”是该记录第n个字段。

  1. [root@server1 ~]# awk -F":" '{print $1}' /etc/passwd
  2. root
  3. bin
  4. daemon
  5. adm
  6. lp
  7. sync
  8. shutdown
  9. halt
  10. mail
  11. operator
  12. games
  13. ftp
  14. nobody
  15. systemd-network
  16. dbus
  17. polkitd
  18. sshd
  19. postfix
  20. chrony
  21. zhangsan
  22. centos
  23. [root@server1 ~]# awk -F':' '{print $1 $3}' /etc/passwd
  24. root0
  25. bin1
  26. daemon2
  27. adm3
  28. lp4
  29. sync5
  30. shutdown6
  31. halt7
  32. mail8
  33. operator11
  34. games12
  35. ftp14
  36. nobody99
  37. systemd-network192
  38. dbus81
  39. polkitd999
  40. sshd74
  41. postfix89
  42. chrony998
  43. zhangsan1000
  44. centos1001
  45. [root@server1 ~]# awk -F":" '{print $1" " $3}' /etc/passwd
  46. root 0
  47. bin 1
  48. daemon 2
  49. adm 3
  50. lp 4
  51. sync 5
  52. shutdown 6
  53. halt 7
  54. mail 8
  55. operator 11
  56. games 12
  57. ftp 14
  58. nobody 99
  59. systemd-network 192
  60. dbus 81
  61. polkitd 999
  62. sshd 74
  63. postfix 89
  64. chrony 998
  65. zhangsan 1000
  66. centos 1001
  67. [root@server1 ~]# awk -F":" '{print "username:"$1"\t\tuid:" $3}' /etc/passwd
  68. username:root uid:0
  69. username:bin uid:1
  70. username:daemon uid:2
  71. username:adm uid:3
  72. username:lp uid:4
  73. username:sync uid:5
  74. username:shutdown uid:6
  75. username:halt uid:7
  76. username:mail uid:8
  77. username:operator uid:11
  78. username:games uid:12
  79. username:ftp uid:14
  80. username:nobody uid:99
  81. username:systemd-network uid:192
  82. username:dbus uid:81
  83. username:polkitd uid:999
  84. username:sshd uid:74
  85. username:postfix uid:89
  86. username:chrony uid:998
  87. username:zhangsan uid:1000
  88. username:centos uid:1001

-F参数:指定分隔符,可指定一个或多个
print 后面做字符串的拼接

实例一:只查看test.txt文件(100行)内第20到第30行的内容(企业面试)

创建文件

  1. [root@server1 ~]# seq 1 100 > test.txt
  1. [root@server1 ~]# awk '{if (NR>=20 && NR<=30) print $0}' test.txt
  2. 20
  3. 21
  4. 22
  5. 23
  6. 24
  7. 25
  8. 26
  9. 27
  10. 28
  11. 29
  12. 30

实例二

已知test.txt文件内容为

  1. [root@server1 ~]# cat test.txt
  2. I am aaron, my qq is 1234567

请从该文件中过滤出 ‘aaron’ 字符串与 ‘1234567’,最后输出的结果为:aaron 1234567

  1. [root@server1 ~]# awk -F '[ ,]+' '{print $3 " " $7}' test.txt
  2. aaron 1234567

[ ,]+这个是正则表达式,+表示一个或多个,这里表示一个或多个空格或逗号

BEGIN和END模块

实例一:统计/etc/passwd的账户人数

  1. [root@server1 ~]# awk '{count++;print $0;} END{print "user count is",count}' /etc/passwd

count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以 ‘;’ 号隔开。这里没有初始化count,虽然默认是0,但是妥当的做法还是初始化为0

  1. [root@server1 ~]# awk 'BEGIN{count=0;print"[start] user count is ",count}{count++;print $0} END{print "[end] user count is ",count}' /etc/passwd
  2. [start] user count is 0
  3. root:x:0:0:root:/root:/bin/bash
  4. bin:x:1:1:bin:/bin:/sbin/nologin
  5. daemon:x:2:2:daemon:/sbin:/sbin/nologin
  6. adm:x:3:4:adm:/var/adm:/sbin/nologin
  7. lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  8. sync:x:5:0:sync:/sbin:/bin/sync
  9. shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
  10. halt:x:7:0:halt:/sbin:/sbin/halt
  11. mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
  12. operator:x:11:0:operator:/root:/sbin/nologin
  13. games:x:12:100:games:/usr/games:/sbin/nologin
  14. ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
  15. nobody:x:99:99:Nobody:/:/sbin/nologin
  16. systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
  17. dbus:x:81:81:System message bus:/:/sbin/nologin
  18. polkitd:x:999:998:User for polkitd:/:/sbin/nologin
  19. sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
  20. postfix:x:89:89::/var/spool/postfix:/sbin/nologin
  21. chrony:x:998:996::/var/lib/chrony:/sbin/nologin
  22. zhangsan:x:1000:1000::/home/zhangsan:/bin/bash
  23. centos:x:1001:2333::/home/centos:/bin/bash
  24. [end] user count is 21

实例二:统计某个文件夹下的文件占用的字节数

  1. [root@server1 ~]# ll
  2. 总用量 136
  3. -rw-------. 1 root root 1241 12 20 15:38 anaconda-ks.cfg
  4. -rw-r--r--. 1 root root 87119 5 26 2016 mha4mysql-manager-0.56-0.el6.noarch.rpm
  5. -rw-r--r--. 1 root root 36326 5 26 2016 mha4mysql-node-0.56-0.el6.noarch.rpm
  6. -rw-r--r--. 1 root root 55 4 11 15:59 test1
  7. -rw-r--r--. 1 root root 29 4 11 21:06 test.txt
  8. [root@server1 ~]# ll | awk 'BEGIN{size=0}{size=size+$5} END{print "size is",size}'
  9. size is 124770

awk运算符

运算符 描述
赋值运算符
= += -= = /= %= ^= *= 赋值语句
逻辑运算符
|| 逻辑或
&& 逻辑与
正则运算符
~ !~ 匹配正则表达式和不匹配正则表达式
关系运算符
< <= > >= != == 关系运算符
算术运算符
+ - 加,减
* / % 乘,除与求余
+ - ! 一元加,减和逻辑非
^ * 求幂
++ — 增加或减少,作为前缀或后缀
其他运算符
$ 字段引用
空格 字符串链接符
?: 三目运算符
ln 数组中是否存在某键值

awk 赋值运算符:a+=5;等价于a=a+5;其他同类

  1. [root@server1 ~]# awk 'BEGIN{a=5;a+=5;print a}'
  2. 10

awk逻辑运算符:判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

  1. [root@server1 ~]# awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'
  2. 0 1

awk正则运算符:

  1. [root@node-1 ~]# awk 'BEGIN{a="100testaa";if(a~/100/) {print "OK"}}'
  2. OK
  3. [root@node-1 ~]# echo | awk 'BEGIN{a="100testaa"}a~/100/{print "OK"}'
  4. OK

关系运算符:
如: > < 可以作为字符串比较,也可以用作数值比较,关键看操作数如果是字符串就会转换为字符串比
较。两个都为数字才转为数值比较。字符串比较:按照ascii码顺序比较。

  1. [root@node-1 ~]# awk 'BEGIN{a="11";if(a>=9){print"OK"}}'
  2. [root@node-1 ~]# awk 'BEGIN{a=11;if(a>=9){print"OK"}}'
  3. OK
  4. [root@node-1 ~]# awk 'BEGIN{a;if(a>=b){print"OK"}}'
  5. OK

awk 算术运算符:
说明,所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为0。

  1. [root@node-1 ~]# awk 'BEGIN{a="b";print a++,++a}'
  2. 0 2
  3. [root@node-1 ~]# awk 'BEGIN{a="20b4";print a++,++a}'
  4. 20 22

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?:

  1. [root@node-1 ~]# awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'
  2. ok
  3. [root@node-1 ~]# awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'
  4. err

常用awk内置变量

变量名 属性
$0 当前记录
$1~$n 当前记录的第1~n个字段
FS 输入字段分隔符,默认是空格
RS 输入记录分隔符,默认是换行符
NF 当前记录字段的个数,就是有多少列
NR 已读出的记录数,就是行号,从1开始
OFS 输出字段分隔符,默认空格
ORS 输出记录分隔符,默认换行

注:内置变量很多,参阅相关资料

字段分隔符 FS
FS=”\t” 表示一个或多个 Tab 分隔

  1. [root@node-1 ~]# cat tab.txt
  2. aa bb cc
  3. [root@node-1 ~]# awk 'BEGIN{FS="\t+"}{print $1,$2,$3}' tab.txt
  4. aa bb cc

FS=”[[:space:]+]” 一个或多个空白空格,默认的,匹配到不符合的就停止

  1. [root@node-1 ~]# awk -F [[:space:]+] '{print $1,$2,$3,$4,$5}' tab.txt
  2. aa bb cc
  3. [root@node-1 ~]# awk -F [[:space:]+] '{print $1,$2}' tab.txt
  4. aa bb

FS=”[“ “:]+” 以一个或多个空格或:分隔

  1. [root@node-1 ~]# awk -F [" ":]+ '{print $1,$2,$3}' hello.txt
  2. root x 0

字段数量 NF :显示满足用:分割,并且有8个字段的

  1. [root@node-1 ~]# awk -F ":" 'NF==8{print $0}' hello.txt
  2. bin:x:1:1:bin:/bin:/sbin/nologin:888

记录数量NR

  1. [root@node-1 ~]# ifconfig br0 | awk -F [" ":]+ 'NR==2{print $3}'
  2. 192.168.0.241

RS 记录分隔符变量
将 FS 设置成”\n”告诉 awk 每个字段都占据一行。通过将 RS 设置成””,还会告诉 awk每个地址记录都由空白行分隔。

  1. [root@node-1 ~]# cat awk.txt
  2. #!/bin/awk
  3. BEGIN {
  4. FS="\n"
  5. RS=""
  6. }
  7. {
  8. print $1","$2","$3
  9. }
  10. [root@node-1 ~]# awk -f awk.txt recode.txt

在””分割符之内,符合\n分割的会被打印出来

OFS 输出字段分隔符

  1. [root@node-1 ~]# awk 'BEGIN{FS=":";OFS="#"}{print $1,$2,$3}' hello.txt
  2. root#x#0
  3. bin#x#1

ORS 输出记录分隔符

  1. [root@node-1 ~]# cat awk.txt
  2. #!/bin/awk
  3. BEGIN {
  4. FS="\n"
  5. RS=""
  6. ORS="\n\n"
  7. }
  8. {
  9. print $1","$2","$3
  10. }
  11. [root@node-1 ~]# awk -f awk.txt recode.txt
  12. Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456
  13. Big Tony,200 Incognito Ave.,Suburbia,WA 64890

awk正则

元字符 功能 示例 解释
^ 首行定位符 /^root/ 匹配所有以root开头的行
$ 行尾定位符 /root$/ 匹配所有以root结尾的行
. 匹配任意单个字符 /r..t/ 匹配字母r,然后两个字符,再以t结尾的行
* 匹配0个或多个前导字符(包括回车) /a*ool/ 匹配0个或多个a之后紧跟着ool的行,比如ool,aaaaool等
+ 匹配1个或多个前导字符 /a+b/ ab,aaab
? 匹配1个或0个前导字符 /a?b/ b,ab
[] 匹配字符组内的任意一个字符 /^[abc]/ 匹配以a或b或c开头的行
[^] 匹配不在指定字符组内任意一个字符 /\^[\^abc]/ 匹配不以字母a或b或c开头的行
() 子表达式组合 /(rool)+/ 表示一个或多个rool组合,当有一些字符需要组合时,使用括号括起来
| 或者 /(root)\|b/ 匹配root或者b的行
\ 转义字符 /a\/\// 匹配a//
~ !~ 匹配 不匹配条件语句 $1~/root/ 匹配第一个字段包含root的所有记录
x{m}
x{m,}
x{m,n}
x重复m次
x重复至少m次
x重复至少m次,但是不超过n次
/(root){3}/
/(root){3,}/
/(root){3,6}/
root重复三次
root至少重复三次
root至少重复三次,至多重复6次

应用

  • 规则表达式

    • awk '/REG/{action} ' file ,/REG/为正则表达式,可以将满足条件的记录送入到 action 进行处理
      1. [root@server1 ~]# awk '/root/{print$0}' /etc/passwd
      2. root:x:0:0:root:/root:/bin/bash
      3. operator:x:11:0:operator:/root:/sbin/nologin
      4. [root@server1 ~]# awk -F":" '$5~/root/{print$0}' /etc/passwd
      5. root:x:0:0:root:/root:/bin/bash
  • 布尔表达式

    • awk '布尔表达式{action}' file仅当对前面的布尔表达式求值为真时, awk 才执行代码块。
      1. [root@server1 ~]# awk -F":" '$5=="root"{print$0}' /etc/passwd
      2. root:x:0:0:root:/root:/bin/bash
      3. [root@server1 ~]# awk -F: '($1=="root")&&($5=="root"){print$0}' /etc/passwd
      4. root:x:0:0:root:/root:/bin/bash

      awk的if、循环和数组

      if

      1. {
      2. if ($1=="foo"){
      3. if ($2=="foo"){
      4. print"uno"
      5. }else{
      6. print"one"
      7. }
      8. }
      9. elseif($1=="bar"){
      10. print "two"
      11. }
      12. else{
      13. print"three"
      14. }
      15. }
      使用 if 语句还可以将代码:
      1. ! /matchme/ { print $1 $3 $4 }
      转换成
      1. {
      2. if ( $0 !~ /matchme/ ) {
      3. print $1 $3 $4
      4. }
      5. }

      循环while/for

      我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。 awk 还有”do…while”循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。
      它类似于其它语言中的”repeat…until”循环。以下是一个示例:
  • do…while示例

    1. {
    2. count=1
    3. do {
    4. print "I get printed at least once no matter what"
    5. } while ( count !=1 )
    6. }

    与一般的 while 循环不同,由于在代码块之后对条件求值, “do…while”循环永远都至少执行一次。换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。

  • for循环

awk 允许创建 for 循环,for循环的执行顺序为initial assignment,然后循环执行code block -> increment -> comparison

  1. for ( initial assignment; comparison; increment ) {
  2. code block
  3. }

以下是一个简短示例

  1. for ( x=1;x<=4;x++ ) {
  2. print "iteration", x
  3. }

break 和 continue
此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。使用这些语句可以更好地控制 awk 的
循环结构。

  1. #!/bin/awk
  2. BEGIN{
  3. x=1
  4. while(1) {
  5. print "iteration",x
  6. if ( x==10 ){
  7. break
  8. }
  9. x++
  10. }
  11. }

continue 语句补充了 break

  1. x=1
  2. while (1) {
  3. if ( x==4 ) {
  4. x++
  5. continue
  6. }
  7. print "iteration", x
  8. if ( x>20 ) {
  9. break
  10. }
  11. x++
  12. }

continue在for中使用

  1. #!/bin/awk
  2. BEGIN{
  3. for (x=1;x<=21;x++){
  4. if (x==4){
  5. continue
  6. }
  7. print "iteration",x
  8. }
  9. }

数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

  1. #!/bin/awk
  2. BEGIN{
  3. cities[1]="beijing"
  4. cities[2]="shanghai"
  5. cities["three"]="guangzhou"
  6. for( c in cities) {
  7. print cities[c]
  8. }
  9. print cities[1]
  10. print cities["1"]
  11. print cities["three"]
  12. }
  13. [root@server1 ~]# awk -f for.sh
  14. guangzhou
  15. beijing
  16. shanghai
  17. beijing
  18. beijing
  19. guangzhou

用 awk 中查看服务器连接状态并汇总

  1. [root@server1 ~]# netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}'
  2. LISTEN 4
  3. ESTABLISHED 1

常用字符串函数

函数 说明
gsub(Ere,Repl,[ln]) 除了正则表达式所有具体值被替代,它和sub函数完全一样执行
sub(Ere,Repl,[ln]) 用Repl参数指定的字符串替换ln参数指定的字符串中的由Ere参数指定的扩展正则表达式的第一个具体值。sub函数返回替换的数量。
出现在Repl参数指定的字符串中的&(和符号)由ln参数指定的与Ere参数指定的扩展正则表达式匹配的字符串替换。如果未指定ln参数,缺省值是整个记录($0记录变量)
index(String1,String2) 在由String1参数指定的字符串中(其中有出现String2指定的参数),返回位置,从1开始编号。如果String2参数不在String1参数中出现,则返回0(零)。
length[(String)] 返回String参数指定的字符串的长度(字符形式)。如果未给出String参数,则返回整个记录的长度($0记录变量)。
blength[(String)] 返回String参数指定的字符串长度(以字节为单位)。如果未给出String参数,则返回整个记录的长度($0记录变量)。
substr(String,M,[N]) 返回具有N参数指定的字符数量子串。子串从String参数指定的字符串获取,其字符串以M指定的位置开始。M参数指定为将Stirng参数中的第一个字符作为编号1。如果未指定N参数,则子串的长度将是M参数指定的位置到String参数的末尾的长度
match(String,Ere) 在String参数指定的字符串中返回位置,从1开始编号,如果Ere参数不出现,则返回0
split(String,A,[Ere]) 将String参数指定的参数分割成数组元素A[1]、A[2]…A[n],并返回n的变量值。此分隔可以通过Ere参数指定的扩展正则表达式进行,或用当前字段分隔符(FS特殊变量来进行,如果没有给出Ere参数)。除非上下文指明特殊元素还应具有一个数字值,否则A数组中的元素用字符串值来创建
tolower(String) 返回String参数指定的字符串,字符串中每个大写参数转换为小写。
toupper(String) 返回String参数指定的字符串,字符串中每个小写参数转换为大写。
sprintf(Format,Expr,Expr,…) 根据Format参数指定的printf子例程格式字符串来格式化Expr参数指定的表达式,并返回最后生成的字符串。
  • 字符串函数应用

在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info

  1. [root@node-1 ~]# awk 'BEGIN{info="this is a test2010test!";gsub(/[0-
  2. 9]+/,"!",info);print info}'
  3. this is a test!test!

如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

  1. [root@node-1 ~]# awk 'BEGIN{info="this is a test2010test!";print
  2. index(info,"test")?"ok":"no found";}'
  3. ok

从第 4 个 字符开始,截取 10 个长度字符串

  1. [root@node-1 ~]# awk 'BEGIN{info="this is a test2010test!";print
  2. substr(info,4,10);}'
  3. s is a tes

分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。 并不是从数组下标1…n 开始、

  1. [root@node-1 ~]# awk 'BEGIN{info="this is a test";split(info,tA," ");print
  2. length(tA);for(k in tA){print k,tA[k];}}'