过滤来自一个文件或标准输入匹配模式内容。除了 grep 外,还有 egrep、fgrep。egrep 是 grep 的扩展,相当于 grep -E。fgrep 相当于 grep -f,用的比较少。
用法
grep [OPTION]... PATTERN [FILE]...
支持的正则 | 描述 |
---|---|
-E,–extended-regexp | 模式是扩展正则表达式(ERE) |
-P,–perl-regexp | 模式是 Perl 正则表达式 |
-e,–regexp=PATTERN | 使用模式匹配,可指定多个模式匹配 |
-f,–file=FILE | 从文件每一行获取匹配模式 |
-i,–ignore-case | 忽略大小写 |
-w,–word-regexp | 模式匹配整个单词 |
-x,–line-regexp | 模式匹配整行 |
-v,–invert-match | 打印不匹配的行 |
输出控制 | 描述 |
---|---|
-m,–max-count=NUM | 输出匹配的结果 num 数 |
-n,–line-number | 打印行号 |
-H,–with-filename | 打印每个匹配的文件名 |
-h,–no-filename | 不输出文件名 |
-o,–only-matching | 只打印匹配的内容 |
-q,–quiet | 不输出正常信息 |
-s, --no-messages | 不输出错误信息 |
-r,–recursive | 递归目录 |
-c,–count | 只打印每个文件匹配的行数 |
–include=FILE_PATTERN | 只检索匹配的文件 |
–exclude=FILE_PATTERN | 跳过匹配的文件 |
–exclude-from=FILE | 跳过匹配的文件,来自文件模式 |
–exclude-dir=PATTERN | 跳过匹配的目录 |
内容行控制 | 描述 |
---|---|
-B,–before-context=NUM | 打印匹配的前几行 |
-A,–after-context=NUM | 打印匹配的后几行 |
-C,–context=NUM | 打印匹配的前后几行 |
–color[=WHEN] | 匹配的字体颜色 |
示例:
# grep -f a b
# grep -v -f a b
# echo "a bc de" |xargs -n1 |grep -e 'a' -e 'bc'
a
bc
# grep -E -v "^$|^#" /etc/httpd/conf/httpd.conf
匹配开头不分大小写的单词
# echo "A a b c" |xargs -n1 |grep -i a
或
# echo "A a b c" |xargs -n1 |grep '[Aa]'
A
a
# echo "this is a test" |grep -o 'is'
is
is
# seq 1 20 |grep -m 5 -E '[0-9]{2}'
10
11
12
13
14
# seq 1 20 |grep -c -E '[0-9]{2}'
11
# echo "a bc de" |xargs -n1 |grep '^b'
bc
# echo "a ab abc abcd abcde" |xargs -n1 |grep -n 'de$'
5:abcde
# grep -r '192.167.1.1' /etc --include *.conf
# grep -r '192.167.1.1' /opt --exclude *.bak
# grep -r '192.167.1.1' /opt --exclude-from file
# seq 41 45 |grep -E '4[12]'
41
42
# seq 13 |grep -E '[0-9]{2}'
10
11
12
13
# echo "a ab abc abcd abcde" |xargs -n1 |grep -E -w -o '[a-z]{2,3}'
ab
abc
# ifconfig |grep -E -o "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
# ifconfig |grep -E -o "[0-9]{1,3}\.{3}[0-9]{1,3}"
# ifconfig | grep -E -o '((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
# seq 1 10 |grep 5 -A 3
5
6
7
8
# seq 1 10 |grep 5 -B 3
2
3
45
# seq 1 10 |grep 5 -C 3
2
3
4
5
6
7
8
## 不显示错误输出:
# grep 'a' abc
grep: abc: No such file or directory
# grep -s 'a' abc
# echo $?
2
## 不显示正常输出:
# grep -q 'a' a.txt
流编辑器,过滤和替换文本。
工作原理:sed 命令将当前处理的行读入模式空间进行处理,处理完把结果输出,并清空模式空间。然后再将下一行读入模式空间进行处理输出,以此类推,直到最后一行。还有一个空间叫保持空间,又称暂存空间,可以暂时存放一些处理的数据,但不能直接输出,只能放到模式空间输出。这两个空间其实就是在内存中初始化的一个内存区域,存放正在处理的数据和临时存放的数据。
用法
sed [OPTION]... {script-only-if-no-other-script} [input-file]...
sed [选项] '地址 命令' file
选项 | 描述 |
---|---|
-n | 不打印模式空间 |
-e | 执行脚本、表达式来处理 |
-f | 执行动作从文件读取执行 |
-i | 修改原文件 |
-r | 使用扩展正则表达式 |
命令 | 描述 |
---|---|
s/regexp/replacement/ | 替换字符串 |
p | 打印当前模式空间 |
P | 打印模式空间的第一行 |
d | 删除模式空间,开始下一个循环 |
D | 删除模式空间的第一行,开始下一个循环 |
= | 打印当前行号 |
a \text | 当前行追加文本 |
i \text | 当前行上面插入文本 |
c \text | 所选行替换新文本 |
q | 立即退出 sed 脚本 |
r | 追加文本来自文件 |
: label | label 为 b 和 t 命令 |
b label | 分支到脚本中带有标签的位置,如果分支不存在则分支到脚本的末尾 |
t label | 如果 s///是一个成功的替换,才跳转到标签 |
h H | 复制/追加模式空间到保持空间 |
g G | 复制/追加保持空间到模式空间 |
x | 交换模式空间和保持空间内容 |
l | 打印模式空间的行,并显示控制字符$ |
n N | 读取/追加下一行输入到模式空间 |
w filename | 写入当前模式空间到文件 |
! | 取反、否定 |
& | 引用已匹配字符串 |
地址 | 描述 |
---|---|
first~step | 步长,每 step 行,从第 first 开始 |
$ | 匹配最后一行 |
/regexp/ | 正则表达式匹配行 |
number | 只匹配指定行 |
addr1,addr2 | 开始匹配 addr1 行开始,直接 addr2 行结束 |
addr1,+N | 从 addr1 行开始,向后的 N 行 |
addr1,~N | 从 addr1 行开始,到 N 行结束 |
匹配打印:
借助以下文本内容作为示例讲解
# tail /etc/services
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
打印匹配axio开头的行
# tail /etc/services | sed -n '/^axio/p'
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
打印第一行
# tail /etc/services | sed -n '1 p'
aigairserver 21221/tcp # Services for Air Server
打印第一行至第三行
# tail /etc/services | sed -n '1,3 p'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
打印奇数行
tail /etc/services | sed -n '1~2 p'
aigairserver 21221/tcp # Services for Air Server
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
axio-disc 35100/tcp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
打印匹配行及后一行
# tail /etc/services | sed -n '/pmw/,+1 p'
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
打印最后一行
# tail /etc/services | sed -n '$ p'
spremotetablet 46998/tcp # Capture handwritten signatures
不打印最会一行
# tail /etc/services | sed -n '$ !p'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
匹配范围
# tail /etc/services | sed -n '/^axio/,/^pmw/ p'
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
匹配开头行到最后一行
# tail /etc/services | sed -n '/^axio/,$ p'
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
引用系统变量,用引号
# tail /etc/services | sed -n "$a,3 p"
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
# tail /etc/services | sed -n ''$a',3 p'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
注意:
匹配删除:
打印是把匹配的打印出来,删除是把匹配的删除,删除只是不用-n 选项。
# tail /etc/services | sed '/axio/ d'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
# tail /etc/services | sed '1 d'
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
# tail /etc/services | sed '1~2 d'
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/udp # Axiomatic discovery protocol
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
spremotetablet 46998/tcp # Capture handwritten signatures
# tail /etc/services | sed '1,3 d'
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
## 去除空格http.conf文件空行或开头#号的行
# sed '/^#/d;/^$/d' /etc/httpd/conf/httpd.conf
替换 s/ / /
替换axio-disc字符串为test
# tail /etc/services | sed 's/axio-disc/test/'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
test 35100/tcp # Axiomatic discovery protocol
test 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
替换开头是axio-disc的字符串并打印
# tail /etc/services | sed -n 's/^axio-disc/test/ p'
test 35100/tcp # Axiomatic discovery protocol
test 35100/udp # Axiomatic discovery protocol
使用&命令引用匹配内容并替换
# tail /etc/services | sed 's/21221/&.0/'
aigairserver 21221.0/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
IP加引号
echo '172.25.254.100 172.25.254.101 172.25.254.102' | sed -r 's/[^ ]+/"&"/g'
"172.25.254.100" "172.25.254.101" "172.25.254.102"
对1-4行的ka-kdp进行替换
# tail /etc/services | sed '1,4s/ka-kdp/test/'
aigairserver 21221/tcp # Services for Air Server
test 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
对匹配行进行替换
tail /etc/services | sed '/21221\/tcp/s/aigairserver/test/'
test 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
二次匹配替换
# tail /etc/services | sed '/21221\/tcp/s/aigairserver/test/;s/ka-kdp/test/'
test 21221/tcp # Services for Air Server
test 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
分组使用,在每个字符串后面添加123
# tail /etc/services | sed -r 's/(.*) (.*)(#.*)/\1\2test \3/'
aigairserver 21221/tcp test # Services for Air Server
ka-kdp 31016/udp test # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp test # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp test # dhanalakshmi.org EDI Service
axio-disc 35100/tcp test # Axiomatic discovery protocol
axio-disc 35100/udp test # Axiomatic discovery protocol
pmwebapi 44323/tcp test # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp test # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp test # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp test # Capture handwritten signatures
将协议与端口号位置调换
# tail /etc/services | sed -r 's/(.*)(\<[0-9]+\>)\/(tcp|udp)(.*)/\1\3\/\2\4/'
aigairserver tcp/21221 # Services for Air Server
ka-kdp udp/31016 # Kollective Agent Kollective Delivery
ka-sddp tcp/31016 # Kollective Agent Secure Distributed Delivery
edi_service udp/34567 # dhanalakshmi.org EDI Service
axio-disc tcp/35100 # Axiomatic discovery protocol
axio-disc udp/35100 # Axiomatic discovery protocol
pmwebapi tcp/44323 # Performance Co-Pilot client HTTP API
cloudcheck-ping udp/45514 # ASSIA CloudCheck WiFi Management keepalive
cloudcheck tcp/45514 # ASSIA CloudCheck WiFi Management System
spremotetablet tcp/46998 # Capture handwritten signatures
位置调换
## 替换x字符为大写
# echo "abc cde xyz" | sed -r 's/(.*)x/\1X/'
abc cde Xyz
## 456与cde调换:
# echo "abc:cde;123:456" | sed -r 's/([^:]+)(;.*:)([^:]+$)/\3\2\1/'
abc:456;123:cde
注释匹配行后的多少行
# seq 10 | sed '/5/,+3s/^/#/'
1
2
3
4
#5
#6
#7
#8
9
10
注释指定多行
# seq 5 | sed -r '/^3|^4/s/^/#/'
1
2
#3
#4
5
# seq 5 | sed -r 's/^3|^4/#\0/'
1
2
#3
#4
5
去除开头和结尾空格或制表符
# echo " 1 2 3 "|sed 's/^[ \t]]*//;s/[ \t]*$//'
1 2 3
多重编辑(-e)
# tail /etc/services | sed -e '1,2d' -e 's/axio-disc/test/'
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
test 35100/tcp # Axiomatic discovery protocol
test 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
## 也可以使用分号分隔
# tail /etc/services | sed '1,2d;s/axio-disc/test/'
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
test 35100/tcp # Axiomatic discovery protocol
test 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
添加新内容(a、i和c)
在axio-disc上一行添加test
# tail /etc/services | sed '/axio-disc/i \test'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
test
axio-disc 35100/tcp # Axiomatic discovery protocol
test
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
在axio-disc下一行添加test
# tail /etc/services | sed '/axio-disc/a \test'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
test
axio-disc 35100/udp # Axiomatic discovery protocol
test
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
将axio-disc替换新行
# tail /etc/services | sed '/axio-disc/c \test'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
test
test
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
在指定行下一行添加一行
# tail /etc/services | sed '2a \test'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
test
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
在指定行的前面和后面添加一行
# seq 5 | sed '3s/.*/txt\n&/'
1
2
txt
3
4
5
# seq 5 | sed '3s/.*/&\ntxt/'
1
2
3
txt
4
5
读取文件并追加到匹配行后(r)
# cat a.txt
123
456
# tail /etc/services | sed '/axio-disc/r a.txt'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
123
456
axio-disc 35100/udp # Axiomatic discovery protocol
123
456
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
将匹配行写入文件(w)
# tail /etc/services | sed '/axio-disc/w b.txt'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
# cat b.txt
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
读取下一行(n和N)
n:读取下一行到模式空间。
N:追加下一行内容到模式空间,并以换行符\n分隔。
打印匹配的下一行
seq 5 | sed -n '/3/{n;p}'
4
打印偶数
# seq 6 | sed -n 'n;p'
2
4
6
## sed 先读取第一行 1,执行 n 命令,获取下一行 2,此时模式空间是 2,执行 p 命令,打印模式空间。 现在模式空间是 2,sed 再读取 3,执行 n 命令,获取下一行 4,此时模式空间为 4,执行 p 命令,以此类推。
打印奇数
# seq 6 | sed 'n;d'
1
3
5
## sed 先读取第一行 1,此时模式空间是 1,并打印模式空间 1,执行 n 命令,获取下一行 2,执行 d命令,删除模式空间的 2,sed 再读取 3,此时模式空间是 3,并打印模式空间,再执行 n 命令,获取下一行 4,执行 d 命令,删除模式空间的 3,以此类推。
每三行执行一次p命令
# seq 6 | sed 'n;n;p'
1
2
3
3
4
5
6
6
## sed 先读取第一行 1,并打印模式空间 1,执行 n 命令,获取下一行 2,并打印模式空间 2,再执行 n命令,获取下一行 3,执行 p 命令,打印模式空间 3。sed 读取下一行 3,并打印模式空间 3,以此类推。
每三行替换一次
## 我们只是把 p 命令改成了替换命令。
# seq 6 | sed 'n;n;s/^/=/;s/$/=/'
1
2
=3=
4
5
=6=
## 这次用到了地址匹配,来实现上面的效果:当执行多个 sed 命令时,有时相互会产生影响,我们可以用大括号{}把他们括起来。
# seq 6 | sed '3~3{s/^/=/;s/$/=/}'
1
2
=3=
4
5
=6=
## 当执行多个 sed 命令时,有时相互会产生影响,我们可以用大括号{}把他们括起来
N:追加下一行内容到模式空间,并以换行符\n分隔。
## sed 读取第一行 1,N 命令读取下一行 2,并以\n2 追加,此时模式空间是 1\n2,再执
行 q 退出。
# seq 6 | sed 'N;q'
1
2
## 执行 N 命令后,此时模式空间是 1\n2,再执行把\n 替换为空,此时模式空间是 12,并打印
# seq 6 | sed 'N;s/\n//'
12
34
56
## N 命令是读取下一行追加到 sed 读取的当前行,当 N 读取下一行没有内容时,则退出,也不会执行 p 命令打印当前行,所以不会打印5。
# seq 5 | sed -n 'N;p'
1
2
3
4
# seq 6 | sed -n 'N;p'
1
2
3
4
5
6
## 打印奇数行的最后一行,加一个满足条件,当 sed 执行到最后一行时,用感叹号不去执行 N 命令,随后执行 p 命令。
# seq 5 | sed -n '$!N;p'
1
2
3
4
5
打印和删除模式空间的第一行(P和D)
P:打印模式空间的第一行。
D:删除模式空间的第一行。
打印奇数
# seq 6 | sed -n 'N;P'
1
3
5
保留最后一行
# seq 6 | sed 'N;D'
6
## 读取第一行 1,执行 N 命令读取下一行并追加到模式空间,此时模式空间是 1\n2,执行 D 命令删除模式空间第一行 1,剩余 2。
读取第二行,执行 N 命令,此时模式空间是 3\n4,执行 D 命令删除模式空间第一行 3,剩余 4。以此类推,读取最后一行打印时,而 N 获取不到下一行则退出,不再执行 D,因此模式空间只剩余 6就打印。
保持空间操作(h与H、g与G和x)
h:复制模式空间内容到保持空间(覆盖)。
H:复制模式空间内容追加到保持空间。
g:复制保持空间内容到模式空间(覆盖)。
G:复制保持空间内容追加到模式空间。
x:模式空间与保持空间内容互换。
将匹配的内容覆盖到另一个匹配
# seq 6 | sed -e '/3/{h;d}' -e '/5/g'
1
2
4
3
6
## h 命令把匹配的 3 复制到保持空间,d 命令删除模式空间的 3。后面命令再对模式空间匹配 5,并用g 命令把保持空间 3 覆盖模式空间 5。
将匹配的内容放到最后
# seq 6 | sed -e '/3/{h;d}' -e '$G'
1
2
4
5
6
3
交换模式空间和保持空间
# seq 6 | sed -e '/3/{h;d}' -e '/5/x' -e '$G'
1
2
4
3
6
5
倒叙输出
# seq 5 | sed '1!G;h;$!d'
5
4
3
2
1
## 1!G 第一行不执行把保持空间内容追加到模式空间,因为现在保持空间还没有数据。
h 将模式空间放到保持空间暂存。
$!d 最后一行不执行删除模式空间的内容。
读取第一行 1 时,跳过 G 命令,执行 h 命令将模式空间 1 复制到保持空间,执行 d 命令删除模式空间的 1。
读取第二行 2 时,模式空间是 2,执行 G 命令,将保持空间 1 追加到模式空间,此时模式空间是2\n1,执行 h 命令将 2\n1 覆盖到保持空间,d 删除模式空间。
读取第三行 3 时,模式空间是 3,执行 G 命令,将保持空间 2\n1 追加到模式空间,此时模式空间是3\n2\n1,执行 h 命令将模式空间内容复制到保持空间,d 删除模式空间。
以此类推,读到第 5 行时,模式空间是 5,执行 G 命令,将保持空间的 4\n3\n2\n1 追加模式空间,然后复制到模式空间,5\n4\n3\n2\n1,不执行 d,模式空间保留,输出。
由此可见,每次读取的行先放到模式空间,再复制到保持空间,d 命令删除模式空间内容,防止输出,再追加到模式空间,因为追加到模式空间,会追加到新读取的一行的后面,循环这样操作, 就把所有行一行行追加到新读取行的后面,就形成了倒叙。
每行后面添加新空行
# seq 5 | sed G
1
2
3
4
5
打印匹配行的上一行
# seq 5 | sed -n '/3/{x;p};h'
2
## 读取第一行 1,没有匹配到 3,不执行{x;p},执行 h 命令将模式空间内容 1 覆盖到保持空间。
读取第二行 2,没有匹配到 3,不执行{x;p},执行 h 命令将模式空间内容 2 覆盖到保持空间。
读取第三行 3,匹配到 3,执行 x 命令把模式空间 3 与保持空间 2 交换,再执行 p 打印模式空间 2.以此类推。
打印匹配行到最后一行或下一行到最后一行
## 打印匹配行到最后一行
# seq 5 |sed -n '/3/,$p'
3
4
5
# seq 5 |sed -n '/3/,${h;x;p}'
3
4
5
# seq 5 |sed -n '/3/{:a;N;$!ba;p}'
3
4
5
## 打印匹配行的下一行到最后一行
# seq 5 |sed -n '/3/{n;:a;N;$!ba;p}'
4
5
## 匹配到 3 时,n 读取下一行 4,此时模式空间是 4,执行 N 命令读取下一行并追加到模式空间,此时模式空间是 4\n5,标签循环完成后打印模式空间 4\n5。
标签(:、b和t)
标签可以控制流,实现分支判断。
:lable name 定义标签。
b lable 跳转到指定标签,如果没有标签则到脚本末尾。
t label 跳转到指定标签,前提是s///命令执行成功。
将换行符替换成逗号
## 方法1
# seq 6 | sed 'N;s/\n/,/'
1,2
3,4
5,6
## 这种方式并不能满足我们的需求,每次 sed 读取到模式空间再打印是新行,替换\n 也只能对 N 命令追加后的 1\n2 这样替换。
## 使用标签::a 是定义的标签名,b a 是跳转到 a 位置。
sed 读取第一行 1,N 命令读取下一行 2,此时模式空间是 1\n2$,执行替换,此时模式空间是1,2$,执行 b 命令再跳转到标签 a 位置继续执行 N 命令,读取下一行 3 追加到模式空间,此时模式空间是 1,2\n3$,再替换,以此类推,不断追加替换,直到最后一行 N 读不到下一行内容退出。
# seq 6 | sed ':a;N;s/\n/,/;b a'
1,2,3,4,5,6
## 方法2:先将每行读入到模式空间,最后再执行全局替换。$!是如果是最后一行,则不执行 b a 跳转,最后执行全局替换。
# seq 6 | sed ':a;N;$!b a;s/\n/,/g'
1,2,3,4,5,6
每三个数字加一个逗号
# echo '123456789' | sed -r ':a ;s/([0-9]+)([0-9]+{3})/\1,\2/;t a'
123,456,789
## 执行第一次时,替换最后一个,跳转后,再对 123456 匹配替换,直到匹配替换不成功,不执行 t 命令。
忽略大小写匹配(I)
# echo -e "a\nA\nb\nc" | sed 's/a/1/Ig'
1
1
b
c
获取总行数($=)
# seq 10 |sed -n '$='
awk 是一个处理文本的编程语言工具,能用简短的程序处理标准输入或文件、数据排序、计算以及生成报表等等。
在 Linux 系统下默认 awk 是 gawk,它是 awk 的 GNU 版本。可以通过命令查看应用的版本:ls -l /bin/awk
awk 处理的工作方式与数据库类似,支持对记录和字段处理,这也是 grep 和 sed 不能实现的。
在 awk 中,缺省的情况下将文本文件中的一行视为一个记录,逐行放到内存中处理,而将一行中的某一部分作为记录中的一个字段。用 1,2,3…数字的方式顺序的表示行(记录)中的不同字段。用$后跟数字,引用对应的字段,以逗号分隔,0 表示整个行。
基本语法命令
awk option 'pattern {action}' file
其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号用于根据特定的模式对一系列指令进行分组。
选项
选项 | 描述 |
---|---|
-f program-file | 从文件中读取 awk 程序脚本源文件 |
-F fs | 指定 fs 为输入字段分隔符 |
-v var=value | 变量赋值 |
–posix | 兼容 POSIX 正则表达式 |
–dump-variables=[file] | 把 awk 命令时的全局变量写入文件,默认文件是awkvars.out |
–profile=[file] | 格式化 awk 语句到文件,默认是 awkprof.out |
模式
Pattern | Description |
---|---|
BEGIN{ } | 给程序赋予初始状态,先执行的工作 |
END{ } | 程序结束之后执行的一些扫尾工作 |
/regular expression/ | 为每个输入记录匹配正则表达式 |
pattern && pattern | 逻辑 and,满足两个模式 |
pattern || pattern | 逻辑 or,满足其中一个模式 |
! pattern | 逻辑 not,不满足模式 |
pattern1, pattern2 | 范围模式,匹配所有模式 1 的记录,直到匹配到模式 2 |
动作:print、流程控制、I/O语句等
从文件读取awk程序处理文件
# vim test.awk
{pringt $2}
# tail -n3 /etc/services | awk -f test.awk
45514/udp
45514/tcp
46998/tcp
指定分隔符,打印指定字段
## 打印第二个字段,默认以空格分隔
# tail -n3 /etc/services | awk '{print $2}'
45514/udp
45514/tcp
46998/tcp
## 指定冒号为分隔符打印第一字段
# awk -F ':' '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
......
指定多个分隔符,作为同一个分隔符处理
# tail -n3 /etc/services | awk -F'[/#]' '{print $3}'
ASSIA CloudCheck WiFi Management keepalive
ASSIA CloudCheck WiFi Management System
Capture handwritten signatures
# tail -n3 /etc/services | awk -F'[ /]' '{print $1}'
cloudcheck-ping
cloudcheck
spremotetablet
# tail -n3 /etc/services | awk -F'/' '{print $1}'
cloudcheck-ping 45514
cloudcheck 45514
spremotetablet 46998
变量赋值
# awk -v a=123 'BEGIN{print a}'
123
## 系统变量作为awk变量的值
# a=123
# awk -v a=$a 'BEGIN{print a}'
123
## 使用单引号
# awk 'BEGIN{print '$a'}'
123
输出awk全局变量到文件
# seq 5 | awk --dump-variables '{print $0}'
1
2
3
4
5
# cat awkvars.out
ARGC: 1
ARGIND: 0
ARGV: array, 1 elements
BINMODE: 0
CONVFMT: "%.6g"
ENVIRON: array, 27 elements
ERRNO: ""
FIELDWIDTHS: ""
FILENAME: "-"
FNR: 5
FPAT: "[^[:space:]]+"
FS: " "
FUNCTAB: array, 41 elements
IGNORECASE: 0
LINT: 0
NF: 1
NR: 5
OFMT: "%.6g"
OFS: " "
ORS: "\n"
PREC: 53
PROCINFO: array, 21 elements
RLENGTH: 0
ROUNDMODE: "N"
RS: "\n"
RSTART: 0
RT: "\n"
SUBSEP: "\034"
SYMTAB: array, 28 elements
TEXTDOMAIN: "messages"
BEGIN 和 END
BEGIN:BEGIN 模式是在处理文件之前执行该操作,常用于修改内置变量、变量赋值和打印输出的页眉或标题。
## 打印页眉
# tail /etc/services | awk 'BEGIN{print "Service\t\tPort\t\t\tDescription\n=="}{print $0}'
Service Port Description
==
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
END:END 模式是在程序处理完才会执行。
## 打印页尾
# tail /etc/services | awk '{print $0}END{print "==\nEND......"}'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
==
END......
格式化输出awk命令到文件
# tail /etc/services | awk --profile 'BEGIN{print "Service\t\tPort\t\t\tDescription\n==="}{print $0}END{print "===\nEND......"}'
Service Port Description
===
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
===
END......
# cat awkprof.out
# gawk profile, created Sun Feb 9 05:17:03 2025
# BEGIN rule(s)
BEGIN {
1 print "Service\t\tPort\t\t\tDescription\n==="
}
# Rule(s)
10 {
10 print $0
}
# END rule(s)
END {
1 print "===\nEND......"
}
/re/正则匹配
# tail /etc/services | awk '/tcp/{print $0}'
aigairserver 21221/tcp # Services for Air Server
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
axio-disc 35100/tcp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
逻辑and、or和not
匹配记录中包含 axio 和 tcp 的行:
# tail /etc/services | awk '/axio/ && /tcp/{print $0}'
axio-disc 35100/tcp # Axiomatic discovery protocol
匹配记录中包含axio 或 tcp 的行:
# tail /etc/services | awk '/axio/ || /tcp/{print $0}'
aigairserver 21221/tcp # Services for Air Server
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
不匹配开头是#和空行:
# awk '! /^#/ && ! /^$/{print $0}' /etc/httpd/conf/httpd.conf
# awk '/^[^#]/ && !/^$/' /etc/httpd/conf/httpd.conf
# awk '/^[^#] | ^$/' /etc/httpd/conf/httpd.conf
匹配范围
# tail /etc/services | awk '/^axio/,/^cloudcheck/'
axio-disc 35100/tcp # Axiomatic discovery protocol
axio-disc 35100/udp # Axiomatic discovery protocol
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
## 对匹配范围后记录再次处理,例如匹配关键字下一行到最后一行:
# seq 5 |awk '/3/,/^$/{printf /3/?"":$0"\n"}'
4
5
# seq 5 | awk '/3/{t=1;next}t'
4
5
## 1 和 2 都不匹配 3,不执行后面{},执行 t,t 变量还没赋值,为空,空在 awk 中就为假,就不打印当前行。匹配到 3,执行 t=1,next 跳出,不执行 t。4 也不匹配 3,执行 t,t 的值上次赋值的 1,为真,打印当前行,以此类推。(非 0 的数字都为真,所以 t 可以写任意非 0 数字)如果想打印匹配行都最后一行,就可以这样了:
# seq 5 | awk '/3/{t=1}t'
3
4
5
内置变量
变量名 | 描述 |
---|---|
FS OFS |
输入字段分隔符,默认是空格或制表符 输出字段分隔符,默认是空格 |
RS ORS |
输入记录分隔符,默认是换行符\n 输出记录分隔符,默认是换行符\n |
NF NR |
统计当前记录中字段个数 统计记录编号,每处理一行记录,编号就会+1 |
FNR | 统计记录编号,每处理一行记录,编号也会+1,与 NR 不同的是,处理第二个文件时,编号会重新计数。 |
ARGC | 命令行参数数量 |
ARGV | 命令行参数数组序列数组,下标从 0 开始,ARGV[0]是 awk |
ARGIND | 当前正在处理的文件索引值。第一个文件是 1,第二个文件是 2,以此类推 |
EVNIRON | 当前系统的环境变量 |
FILENAME | 输出当前处理的文件名 |
IGNORECASE | 忽略大小写 |
SUBSEP | 数组中下标的分隔符,默认为"\034" |
示例:
FS和OFS
## 在程序开始前重新赋值 FS 变量,改变默认分隔符为冒号,与-F 一样。
# awk 'BEGIN{FS=":"}{print $1,$2}' /etc/passwd | head -5
root x
bin x
daemon x
adm x
lp x
## 也可以使用-v来重新赋值这个变量
# awk -vFS=":" '{print $1,$2}' /etc/passwd | head -5
root x
bin x
daemon x
adm x
lp x
##由于OFS默认是以空格分隔,反向引用多个字段分隔也是空格,如果想指定输出分隔符这样;
# awk 'BEGIN{FS=":";OFS=":"}{print $1,$2}' /etc/passwd | head -n5
root:x
bin:x
daemon:x
adm:x
lp:x
## 也可以通过字符串拼接实现分隔
awk 'BEGIN{FS=":"}{print $1"#"$2}' /etc/passwd|head -5
root#x
bin#x
daemon#x
adm#x
lp#x
RS和ORS
## RS默认是\n分隔每行,如果想指定以某个字符作为分隔符来处理记录;
# echo "www.baidu.com/user/test.html" | awk 'BEGIN{RS="/"}{print $0}'
www.baidu.com
user
test.html
## RS也支持正则,简单演示
# seq -f "str%02g" 10 | sed 'n;n;a\---'| awk 'BEGIN{RS="-+"}{print $1}'
str01
str04
str07
str10
## 将输出的换行符替换为+号;
# seq 10 | awk 'BEGIN{ORS="+"}{print $0}'
1+2+3+4+5+6+7+8+9+10+
##替换某个字符
# tail -n2 /etc/services | awk 'BEGIN{RS="/";ORS="#"}{print $0}'
cloudcheck 45514#tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998#tcp # Capture handwritten signatures
NF:NF是字段个数
# echo "a b c d e f"|awk '{print NF}'
6
## 打印最后一个字段:
# echo "a b c d e f"|awk '{print $NF}'
f
## 打印倒数第二个字段:
# echo "a b c d e f"|awk '{print $(NF-1)}'
e
## 排除最后两个字段:
# echo "a b c d e f"|awk '{$NF="";$(NF-1)="";print $0}'
a b c d
## 排除第一个字段:
# echo "a b c d e f"|awk '{$1="";print $0}'
b c d e f
NR和FNR
NR 统计记录编号,每处理一行记录,编号就会+1,FNR 不同的是在统计第二个文件时会重新计数。
## 打印行数
# tail -n5 /etc/services|awk '{print NR,$0}'
1 axio-disc 35100/udp # Axiomatic discovery protocol
2 pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
3 cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
4 cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
5 spremotetablet 46998/tcp # Capture handwritten signatures
## 打印总行数
# tail -n5 /etc/services|awk 'END{print NR}'
5
## 打印第三行
# tail -n5 /etc/services|awk 'NR==3'
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
## 打印第三行的第二个字段
# tail -n5 /etc/services|awk 'NR==3{print $2}'
45514/udp
## 打印前三行
# tail -n5 /etc/services|awk 'NR<=3{print NR,$0}'
1 axio-disc 35100/udp # Axiomatic discovery protocol
2 pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
3 cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
接下来,我们来看看NR和FNR的区别
[root@openEulter-1 ~]# cat a.txt
a
b
c
[root@openEulter-1 ~]# cat b.txt
c
d
e
[root@openEulter-1 ~]# awk '{print NR,FNR,$0}' a.txt b.txt
1 1 a
2 2 b
3 3 c
4 1 c
5 2 d
6 3 e
## 我们可以发现:NR 每处理一行就会+1,而 FNR 在处理第二个文件时,编号重新计数。同时也知道 awk 处理两个文件时,是合并到一起处理。
[root@openEulter-1 ~]# awk 'FNR==NR{print $0"1"}FNR!=NR{print $0"2"}' a.txt b.txt
a1
b1
c1
c2
d2
e2
## 当 FNR==NR 时,说明在处理第一个文件内容,不等于时说明在处理第二个文件内容。
ARGC和ARGV
ARGC:是命令行参数数量;
ARGV:是将命令行参数存到数组,元素由ARGC指定,数组下标从0开始
[root@openEulter-1 ~]# awk 'BEGIN{print ARGC}' 1 2 3
4
[root@openEulter-1 ~]# awk 'BEGIN{print ARGV[0]}'
awk
[root@openEulter-1 ~]# awk 'BEGIN{print ARGV[1]}' 1 2
1
[root@openEulter-1 ~]# awk 'BEGIN{print ARGV[2]}' 1 2
2
ARGIND
ARGIND是当前正在处理的文件索引值,第一个文件是1,第二个文件是2,以此类推,从而可以通过这种方式判断正在处理哪个文件。
[root@openEulter-1 ~]# awk '{print ARGIND,$0}' a.txt b.txt
1 a
1 b
1 c
2 c
2 d
2 e
[root@openEulter-1 ~]# awk 'ARGIND==1{print "a->"$0}ARGIND==2{print "b->"$0}' a.txt b.txt
a->a
a->b
a->c
b->c
b->d
b->e
ENVIRON
ENVIRON调用系统变量
[root@openEulter-1 ~]# awk 'BEGIN{print ENVIRON["HOME"]}'
/root
## 如果是设置的环境变量,还需要用export导入到系统变量中才能调用
[root@openEulter-1 ~]# awk 'BEGIN{print ENVIRON["a"]}'
[root@openEulter-1 ~]# export a=123
[root@openEulter-1 ~]# awk 'BEGIN{print ENVIRON["a"]}'
123
FILENAME
FILENAME是当前处理文件的文件名
[root@openEulter-1 ~]# awk 'FNR==NR{print FILENAME"->"$0}FNR!=NR{print FILENAME"->"$0}' a.txt b.txt
a.txt->a
a.txt->b
a.txt->c
b.txt->c
b.txt->d
b.txt->e
IGNORECASE
IGNORECASE=1代表忽略大小写
[root@openEulter-1 ~]# echo "A a b c"|xargs -n1|awk 'BEGIN{IGNORECASE=1}/a/'
A
a
操作符
运算符 | 描述 |
---|---|
(…) | 分组 |
$ | 字段引用 |
++ – | 递增和递减 |
+ - ! | 加号:将字符串转化为数字,如果字符串以数字开头,则提取数字部分并输出,否则输出0 减号:将字符串转化为数字,如果字符串以数字开头,则提取数字部分并取反输出,否则输出0 逻辑否定 |
| |& | 乘、除、取余 |
< > <= >= != == | 关系运算符 |
~ !~ | 正则表达式匹配,否定正则表达式匹配 |
in | 数组成员 |
&& || | 逻辑and、逻辑or |
?: | 简写条件表达式:expr1 ? expr2 : expr3 第一个表达式为真,执行 expr2,否则执行 expr3 |
= += -= *= /= %= ^= | 变量赋值运算符 |
注意:
在 awk 中,有 3 种情况表达式为假:数字是 0,空字符串和未定义的值。
数值运算,未定义变量初始值为 0。字符运算,未定义变量初始值为空。
[root@openEulter-1 ~]# awk 'BEGIN{s="";if(s)print "true";else print"false"}' false [root@openEulter-1 ~]# awk 'BEGIN{n=0;if(n)print "true";else print "false"}' false [root@openEulter-1 ~]# awk 'BEGIN{if(n)print "true";else print "false"}' false
示例:
截取整数
[root@openEulter-1 ~]# echo "123abc abc123 123abc123"|xargs -n1 | awk '{print +$0}'
123
0
123
[root@openEulter-1 ~]# echo "123abc abc123 123abc123"|xargs -n1 | awk '{print -$0}'
-123
0
-123
感叹号
# 打印奇数行
[root@openEulter-1 ~]# seq 6| awk 'i=!i'
1
3
5
## 解释:当处理第一行输入时,执行 i=!i。此时 i 初始值为 0(false),!i 则为 1(true),并将 1 赋值给 i。由于 i 的值为 1(true),在 awk 中,条件为真时会默认执行 print 操作,所以会输出当前行,即 1。
当处理第二行输入时,再次执行 i=!i。此时 i 的值为 1(true),!i 为 0(false),并将 0 赋值给 i。因为 i 的值为 0(false),所以不会输出当前行。
当处理第三行输入时,又执行 i=!i。此时 i 的值为 0(false),!i 为 1(true),并将 1 赋值给 i。由于 i 的值为 1(true),所以会输出当前行,即 3。
以此类推,对于后续的每一行输入,i 的值会在 0 和 1 之间交替变化,导致奇数行对应的 i 值为 1(true)而被输出,偶数行对应的 i 值为 0(false)而不被输出
# 打印偶数行
[root@openEulter-1 ~]# seq 6| awk '!(i=!i)'
2
4
6
不匹配某行
[root@openEulter-1 ~]# tail /etc/services | awk '!/axio/{print $0}'
aigairserver 21221/tcp # Services for Air Server
ka-kdp 31016/udp # Kollective Agent Kollective Delivery
ka-sddp 31016/tcp # Kollective Agent Secure Distributed Delivery
edi_service 34567/udp # dhanalakshmi.org EDI Service
pmwebapi 44323/tcp # Performance Co-Pilot client HTTP API
cloudcheck-ping 45514/udp # ASSIA CloudCheck WiFi Management keepalive
cloudcheck 45514/tcp # ASSIA CloudCheck WiFi Management System
spremotetablet 46998/tcp # Capture handwritten signatures
乘法和除法及取模
[root@openEulter-1 ~]# seq 5 | awk '{print $0*2}'
2
4
6
8
10
[root@openEulter-1 ~]# seq 5 | awk '{print $0/2}'
0.5
1
1.5
2
2.5
[root@openEulter-1 ~]# seq 5 | awk '$0%2==0{print $0}'
2
4
[root@openEulter-1 ~]# seq 5 | awk '$0%2!=0{print $0}'
1
3
5
管道符的使用
[root@openEulter-1 ~]# seq 5 | shuf | awk '{print $0|"sort"}'
1
2
3
4
5
## shuf 命令用于对输入的行进行随机排序
## print $0|"sort":这是一个管道操作。print $0 会将当前行的内容输出,| 是管道符号,它将 print 的输出传递给 sort 命令。sort 命令用于对输入的行进行排序,默认是按字典序升序排列。
正则表达式匹配
[root@openEulter-1 ~]# seq 5 | awk '$0~3{print $0}'
3
[root@openEulter-1 ~]# seq 5 | awk '$0!~3{print $0}'
1
2
4
5
[root@openEulter-1 ~]# seq 5 | awk '$0~/[34]/{print $0}'
3
4
[root@openEulter-1 ~]# seq 5 | awk '$0!~/[34]/{print $0}'
1
2
5
[root@openEulter-1 ~]# seq 5 | awk '$0~/[^34]/{print $0}'
1
2
5
判断数组成员
[root@openEulter-1 ~]# awk 'BEGIN{a["a"]=123}END{if("a" in a)print"yes"}'
三目运算符
[root@openEulter-1 ~]# awk 'BEGIN{print 1==1?"yes":"no"}'
yes
[root@openEulter-1 ~]# seq 5 | awk '{print n=(n?n","$0:$0)}'
1
1,2
1,2,3
1,2,3,4
1,2,3,4,5
## 解释:n?n","$0:$0:这是一个三元运算符表达式,其语法为 条件?表达式1:表达式2。如果条件为真,则返回表达式 1 的值;如果条件为假,则返回表达式 2 的值。
当处理第一行输入时,n 初始值为空字符串,在布尔语境下相当于 false。所以 n?n","$0:$0 会返回 $0,即当前行的内容。此时 n 被赋值为当前行内容 1,并通过 print 输出 1。
当处理第二行输入时,n 已经被赋值为 1,在布尔语境下为 true。所以 n?n","$0:$0 会返回 n","$0,也就是将 n 的值(即 1)和当前行内容 2 用逗号连接起来,得到 1,2。然后将 1,2 赋值给 n 并输出。
当处理第三行输入时,n 的值为 1,2,为 true。n?n","$0:$0 返回 n(即 1,2)和当前行内容 3 用逗号连接的结果 1,2,3,再将其赋值给 n 并输出。
以此类推,对于后续的每一行输入,都会将之前积累的内容 n 和当前行内容用逗号连接起来,更新 n 的值并输出。
# 每三行后面添加新一行
[root@openEulter-1 ~]# seq 10 | awk '{print NR%3?$0:$0"\ntxt"}'
1
2
3
txt
4
5
6
txt
7
8
9
txt
10
# 两行合并一行
[root@openEulter-1 ~]# seq 6|awk '{printf NR%2!=0?$0" ":$0" \n"}'
1 2
3 4
5 6
[root@openEulter-1 ~]# seq 6|awk 'ORS=NR%2?" ":"\n"'
1 2
3 4
5 6
## 解释:
ORS:ORS 是 awk 的内置变量,代表输出记录分隔符(Output Record Separator),默认值是换行符 \n。awk 在输出每一行内容后,会自动添加 ORS 所代表的分隔符。
NR:NR 也是 awk 的内置变量,它表示当前处理的行号,从 1 开始计数。
NR%2:使用取模运算符 % 计算当前行号除以 2 的余数。如果余数为 1,说明当前行号是奇数;如果余数为 0,说明当前行号是偶数。
NR%2?" ":"\n":这是一个三元运算符表达式,语法为 条件?表达式1:表达式2。如果 NR%2 的结果为真(即余数为 1,当前行号是奇数),则返回表达式 1 的值,即空格 " ";如果 NR%2 的结果为假(即余数为 0,当前行号是偶数),则返回表达式 2 的值,即换行符 "\n"。
ORS=NR%2?" ":"\n":将三元运算符的结果赋值给 ORS。这意味着,当处理奇数行时,ORS 被设置为空格 " ";当处理偶数行时,ORS 被设置为换行符 "\n"
[root@openEulter-1 ~]# seq 6 | awk '{if(NR%2)ORS=" ";else ORS="\n";print}'
1 2
3 4
5 6
变量赋值
# 字段求和
## sum未初始化,默认值为0
[root@openEulter-1 ~]# seq 5 | awk '{sum+=1}END{print sum}'
5
[root@openEulter-1 ~]# seq 5 | awk '{sum+=$0}END{print sum}'
15
[root@openEulter-1 ~]# awk ‘BEGIN{print 1==1?“yes”:“no”}’
yes
[root@openEulter-1 ~]# seq 5 | awk ‘{print n=(n?n","$0:$0)}’
1
1,2
1,2,3
1,2,3,4
1,2,3,4,5
当处理第一行输入时,n 初始值为空字符串,在布尔语境下相当于 false。所以 n?n",“$0:$0 会返回 $0,即当前行的内容。此时 n 被赋值为当前行内容 1,并通过 print 输出 1。
当处理第二行输入时,n 已经被赋值为 1,在布尔语境下为 true。所以 n?n”,“$0:$0 会返回 n”,“$0,也就是将 n 的值(即 1)和当前行内容 2 用逗号连接起来,得到 1,2。然后将 1,2 赋值给 n 并输出。
当处理第三行输入时,n 的值为 1,2,为 true。n?n”,"$0:$0 返回 n(即 1,2)和当前行内容 3 用逗号连接的结果 1,2,3,再将其赋值给 n 并输出。
以此类推,对于后续的每一行输入,都会将之前积累的内容 n 和当前行内容用逗号连接起来,更新 n 的值并输出。
[root@openEulter-1 ~]# seq 10 | awk ‘{print NR%3?$0:$0"\ntxt"}’
1
2
3
txt
4
5
6
txt
7
8
9
txt
10
[root@openEulter-1 ~]# seq 6|awk ‘{printf NR%2!=0?$0" “:$0” \n"}’
1 2
3 4
5 6
[root@openEulter-1 ~]# seq 6|awk ‘ORS=NR%2?" “:”\n"’
1 2
3 4
5 6
ORS:ORS 是 awk 的内置变量,代表输出记录分隔符(Output Record Separator),默认值是换行符 \n。awk 在输出每一行内容后,会自动添加 ORS 所代表的分隔符。
NR:NR 也是 awk 的内置变量,它表示当前处理的行号,从 1 开始计数。
NR%2:使用取模运算符 % 计算当前行号除以 2 的余数。如果余数为 1,说明当前行号是奇数;如果余数为 0,说明当前行号是偶数。
NR%2?" “:”\n":这是一个三元运算符表达式,语法为 条件?表达式1:表达式2。如果 NR%2 的结果为真(即余数为 1,当前行号是奇数),则返回表达式 1 的值,即空格 " “;如果 NR%2 的结果为假(即余数为 0,当前行号是偶数),则返回表达式 2 的值,即换行符 “\n”。
ORS=NR%2?” “:”\n":将三元运算符的结果赋值给 ORS。这意味着,当处理奇数行时,ORS 被设置为空格 " “;当处理偶数行时,ORS 被设置为换行符 “\n”
[root@openEulter-1 ~]# seq 6 | awk '{if(NR%2)ORS=” “;else ORS=”\n";print}’
1 2
3 4
5 6
变量赋值
# 字段求和
## sum未初始化,默认值为0
[root@openEulter-1 ~]# seq 5 | awk '{sum+=1}END{print sum}'
5
[root@openEulter-1 ~]# seq 5 | awk '{sum+=$0}END{print sum}'
15