sed and awk

今天花了一下午的时间把 sed,awk 的基础用法看了一下。还没工作,现在暂时用的不多,因此写个笔记整理一下,以便之后快速回忆。

要理解 sed 和 awk 的用法,有座大山必须要先搬走,那就是「正则表达式」。正则表达式用于文本匹配,对于 sed 、 awk 来说就是要把想处理的目标文本,从茫茫的字海中提取出来。

正则表达式

正则表达式若不经常用那真是屡看屡忘,百试不爽。那么正则表达式应该如何正确记忆呢?-分层

类似算法中的分治思想,记忆正则表达时也可遵循此法。遇到一个大问题时我们可先将问题进行拆分,当将每一小问题都妥善解决时,大问题便也解决了。正则表达的拆分可以这样看:
|表达式 |
|:-:|
|字符串表示|
|单个字符表示|

单个字符表示

  • 特定字符表示,就是具体的某一个字符。直接输入该字符就可以。
  • 范围内字符,[] <-放在中括号内的字符。如[0-9]表示范围0~9中的一个字符,记住范围内字符是表示其中的一个字符。此外中括号还可放入其他范围如:
    • [a-z]表示所有小写字母
    • [A-Z]表示所有大写字母
    • [a-zA-Z]表示所有字母
    • [a-zA-Z0-9_] 表示字类字符,与\w等价。(字类字符可以理解为能给变量命名的字符
    • [^a-z]表示除小写字母外的所有字符
  • 任意字符 . 点表示任意一个字符
  • 其他符号
    • ^ 在中括号内表示取反,在中括号外表示单词的开头。
    • 元字符:\w 表示字类字符,\W 表示非字类字符,\b 分隔符

字符串表示

单个字符拼凑起来便是字符串,如要查找 /etc/passwd 文件中以 t 开头 g 结尾的记录:

1
grep 't.*g' /etc/passwd

注意正则表达式是贪婪匹配,即是它会在一行中找到尽量长的匹配结果。因此在写正则表达式的时候,可能需要我们多加注意。大多时候得到理想的匹配结果,都是经过我们多次修改表达式,来一步一步实现的结果。因此需要耐心细致,思考周全。

表达式

即字符串的组合

  • * 表示出现0次或多次,
  • + 表示出现1次或多次,
  • ?表示出现0次或1次
  • {n,m} 重复特定次数,n~m 次

案例一,匹配5~10位的 QQ 号(注意{}需要加转义字符):

1
grep '[0-9]\{5,10\}' qq.txt

案例二,匹配15位或18位身份证号,支持带 x (身份证号第一位不为0,() 需要加转移字符,| 逻辑或需要加转义字符):

1
grep '^[1-9]\([0-9]\{13\} \| [0-9]{16}\)[0-9xX]$'

sed

MAC 系统上是 BSD 版本的 sed ,和 GNU 的某些操作不一样!!!下文是记录的 GNU 系统下的 sed 命令,若在 MAC 上先装 GNU-SED

1
brew install gnu-sed --with-default-names

sed 是流处理编辑器,从文本或管道读取数据到模式空间(临时缓冲区)中,通过 sed 命令处理然后输出。sed 每次只处理一行数据。

sed_流程

sed 处理:

  1. 如何进行文本处理的
  2. 常用命令
  3. 高级操作命令

如何进行文本处理呢?

1.正则选定文本 -> 2. sed进行处理

命令行模式:

1
sed [option] 'command' files

options: -e, -n(quiet)

command: 行定位(正则) + sed 命令

行定位:

  • 定位1行: x, /patterm/
  • 定位多行x,y
  • 不选某行 x!
  • 定位间隔 first~step
  • a新增行,c 替代行,d 删除行,s 替换(分割符/ 、#),g 全局标志

打印第十行

1
sed -n '10p' /etc/passwd

打印第10~20行

1
sed -n '10,20p' /etc/passwd

打印日志中 Error 的行, //是正则表达式部分

1
sed -n '/Error/p' log.txt

打印主机网络接口的 ip 地址

1
2
3
4
5
6
7
8
9
10
先查看接口信息
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether 8c:85:90:cb:10:70
inet6 fe80::801:55c8:cc5e:acc6%en0 prefixlen 64 secured scopeid 0x6
inet 172.17.131.14 netmask 0xfffff000 broadcast 172.17.143.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
----------------------------
ifconfig en0 | sed -n '/inet /p' | sed 's/inet \([0-9.]\+\).*/\1/'

高级操作命令

  • {} 多个 sed 命令,用;分开
  • & 替换固定字符
    案例,小写转大写

    1
    sed 's/\(\w\+\):.*/\1/' passwd | sed 's/.*/\U&/'
  • -r 复制指定文件到匹配行 (插入)

    1
    sed '1r abc.txt' 123.txt  # abc.txt文件拷贝到目标文件第一行之后
  • -w 复制匹配行拷贝到指定文件里 (改写源文件)

  • -q 退出

awk

可编程,处理灵活。方便统计文本,制表。

  1. awk 的行处理方式与格式
  2. awk 内嵌参数应用
  3. awk 内嵌程序代码应用

awk 处理方式

  1. 一次处理一行
  2. awk 可对每行切片处理

命令行格式:

1
awk [options] 'command' files

基本格式 + 扩展格式 : pattern {awk 操作命令}

内置参数

  1. 内置变量, $0 表示当前行,$1表示第一个字段,$2表示第二个字段以此类推
  2. 分隔符, -F : ‘分隔符’
  3. NR: 每行记录号
  4. NF:字段数数量变量
  5. FILENAME:正在处理文件的文件名
    案例1,打印行号,列数,用户名
    1
    awk -F ':' '{print NR, NF, $1}' /etc/passwd

or

1
awk -F ':' '{printf("%s, %s, %s\n", NR, NF, $1)}' /etc/passwd

案例2,显示/etc/passwd 中用户 id 大于100的行号和用户名

1
awk -F ':' '{if ($3 > 100) print $3, $1}' /etc/passwd

内嵌程序应用

逻辑判断式: pattern {awk 命令}

pattern 表示为: 正则表达式;逻辑表达式

  1. ~表示匹配正则表达式,!~表示不匹配正则表达式
  2. ==, != , < , > 常见的判断逻辑

案例1,打印出日志文件中为 Error 行的时间戳

1
sed '/Error/p' log | awk '{print $1}'

or

1
awk '/Error/{print $1}' log

案例2,统计主机处于连接状态和监听状态的描述符数量

1
netstat -anp | awk '$6~/CONNECTED|LISTEN/{sum[$6]++}END{for(i in sum) print i, sum[i]}'