shell文本处理
一、grep
过滤来自一个文件或标准输入匹配模式内容。除了 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] 匹配的字体颜色 -
示例:
- 输出 b 文件中在 a 文件相同的行
# grep -f a b
- 输出 b 文件中在 a 文件不同的行
# grep -v -f a b
- 匹配多个模式
# echo "a bc de" |xargs -n1 |grep -e 'a' -e 'bc' a bc
- 去除空格 http.conf 文件空行或开头#号的行
# 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
- 匹配 b 字符开头的行
# echo "a bc de" |xargs -n1 |grep '^b'bc
- 匹配 de 字符结尾的行并输出匹配的行
# echo "a ab abc abcd abcde" |xargs -n1 |grep -n 'de$' 5:abcde
- 递归搜索/etc 目录下包含 ip 的 conf 后缀文件
# grep -r '192.167.1.1' /etc --include *.conf
- 排除搜索 bak 后缀的文件
# grep -r '192.167.1.1' /opt --exclude *.bak
- 排除来自 file 中的文件
# grep -r '192.167.1.1' /opt --exclude-from file
- 匹配 41 或 42 的数字
# seq 41 45 |grep -E '4[12]' 41 42
- 匹配至少 2 个字符
# seq 13 |grep -E '[0-9]{2}' 10 11 12 13
- 匹配至少 2 个字符的单词,最多 3 个字符的单词
# echo "a ab abc abcd abcde" |xargs -n1 |grep -E -w -o '[a-z]{2,3}' ab abc
- 匹配所有 IP
# 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]?)'
- 打印匹配结果及后 3 行
# seq 1 10 |grep 5 -A 3 5 6 7 8
- 打印匹配结果及前 3 行
# seq 1 10 |grep 5 -B 3 2 3 45
- 打印匹配结果及前后 3 行
# 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 命令将当前处理的行读入模式空间进行处理,处理完把结果输出,并清空模式空间。然后再将下一行读入模式空间进行处理输出,以此类推,直到最后一行。还有一个空间叫保持空间,又称暂存空间,可以暂时存放一些处理的数据,但不能直接输出,只能放到模式空间输出。这两个空间其实就是在内存中初始化的一个内存区域,存放正在处理的数据和临时存放的数据。
-
用法
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
-
注意:
- sed 命令用单引号时,里面变量用单引号引起来,或者 sed 命令用双引号,因为双引号解释特殊符号原有意义。
- 感叹号也就是对后面的命令取反。
-
-
匹配删除:
打印是把匹配的打印出来,删除是把匹配的删除,删除只是不用-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 12345
-
打印匹配行的上一行
# 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
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 keepaliveASSIA CloudCheck WiFi Management SystemCapture 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
输出记录分隔符,默认是换行符\nNF
NR统计当前记录中字段个数
统计记录编号,每处理一行记录,编号就会+1FNR 统计记录编号,每处理一行记录,编号也会+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"}'</dev/null 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?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
-