shell 三剑客基础知识总结

摘要:本文是对 grep 、 awk 、 sed 知识点的记录和总结。

如果你从来没有使用过它们,推荐观看下面的博客,非常通俗易懂:
grep: http://www.zsythink.net/archives/1733
awk: http://www.zsythink.net/archives/tag/awk/page/2/

grep

grep (global search regular expression(RE) and print out the line) 是一个基于正则表达式的全局文本搜索工具,并能将匹配到的文本按行打印。

基本用法

# grep [选项] 正则表达式 [目标文件]
grep [OPTIONS] PATTERN [FILE...]    

# grep [选项] -e 正则表表达式 或 -f 包含正则表表达式的文件 [目标文件]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]   

常用选项

-v:输出不带关键字的行(反向查询,反向匹配)

-n:显示结果所在行号

-i:在搜索的时候忽略大小写

-o:只显示符合条件的字符串,但是不整行显示,每个符合条件的字符串单独显示一行

-r: 当前目录所有文件中查找

-e:实现多个选项的匹配,逻辑 or 关系

-E:使用扩展正则表达式,而不是基本正则表达式,在使用 "-E" 选项时,相当于使用 egrep

-w:匹配整个单词,如果是字符串中包含这个单词,则不作匹配

-c:统计匹配到的行数,注意,是匹配到的总行数,不是匹配到的次数

-Ax:在输出的时候包含结果所在行之后的指定行数,这里指之后的x行,A:after

-Bx:在输出的时候包含结果所在行之前的指定行数,这里指之前的x行,B:before

-Cx:在输出的时候包含结果所在行之前和之后的指定行数,这里指之前和之后的 x 行,C:context

-P:表示使用兼容 perl 的正则规则

awk

特点:1. 报告生成器,强大而自由的文本格式化工具,完全自定义的输入输出格式。2. 一门编程语言,支持判断数组循环。

基本用法

awk [OPTION] 'program' FILE..
awk [OPTION] '[pattern]{action}' FILE..

通常 program 可细分为 pattern 和 action 两部分。

基本概念
记录:以下面的文本内容为例,每一行为一个记录,行分隔符为换行符 \n。
字段:每一行被空格隔开的内容为一个字段,每一行的第一个字段可以用 $1 引用,以此类推,第二、三字段用 $2$3 引用,$0 代表一行的所有字段。

a b c
d e f
g h i

变量

内置变量
FS: 字段分隔符 (field separator) 又称为输入字段分隔符,是 awk 最常用的一个变量, 设置字段分隔符可以将文本按想要的格式分割成若干字段,FS 默认为空格。

$ echo aaa:bbb:ccc | awk -v FS=":" '{print $1,$2,$3}'
aaa bbb ccc

OFS: 输出字段分隔符(output field separator),字段在标准输出输出时的分割符,默认为空格。

$ echo aaa:bbb:ccc | awk -v FS=":" -v OFS="#" '{print $1,$2,$3}'
aaa#bbb#ccc

RS: 记录分隔符(record separator),awk 默认以一行为1个记录,默认记录分隔符为 \n 换行符,改变 RS,则以新符号为一个记录。

$ echo aaa:bbb:ccc | awk -v RS=":" '{print $1,$2,$3}'
aaa
bbb
ccc

ORS: 输出记录分隔符(output record separator),同理 OFS,默认值为 \n。

$ echo -e "aaa\nbbb\nccc"| awk -v ORS="#" '{print $1}'
aaa#bbb#ccc#

NF: 字段个数(number of field),每一行记录里被字段分隔符分隔出来的字段数量。

$ echo "aa bb cc" | awk '{print NF}'
3

NR: 记录分隔符(number of record),被处理的文本被记录分隔符分隔的记录数。

$ echo -e "aaa\nbbb\nccc"| awk 'END{print NR}'
3

FNR: 处理多个输入文件时,各文件分别计数的记录分隔符。
FILENAME:输入文件的文件名,没有文件时,默认值为 - 。
ARGC:命令行参数的个数
ARGV:数组,保存的是命令行所给定的各参数 awk 本身是第一个参数

自定义变量
awk 允许自定义变量,使用 -v 选项,引用时直接使用名称,不用加 $。

action

常用 action 包括 print、printf、和代码块。

printf 与 printf 命令类似,可以用来格式化输出文本。

$ echo "1 2 3" | awk '{printf "%s,%2s,%.2f\n",$1,$2,$3}'
1, 2,3.00

$ cat /etc/passwd | awk -v FS=":" '{printf "%-10s\t %s\n",$1,$3}' | head -3
root           0
bin            1
daemon         2

代码块
用 {} 包裹的内容即为代码块 action,支持流程控制语句,if…eles, 三目运算, for, for in, while, exit, next 等,句末用 ; 分隔。

$ echo -e "a b c\nd e f\ng h i" | awk '{if(NR==1){print $2}else{print $0};}'
b
d e f
g h i

pattern

awk [OPTION] '[pattern]{action}' FILE..

空模式
当没有 [pattern] 时,则为空模式,所有记录都会执行 {action} 内的动作。

BEGIN END 模式
这是一种特殊的模式,BEGIN 在记录处理开始之前执行紧随的代码块里的内容,END 则在记录处理结束之后执行紧随其后代码块里的内容。

$ echo -e "a b c\nd e f\ng h i" | awk 'BEGIN{print 1,2,3} {print $0} END{print 1,2,3}'
1 2 3
a b c
d e f
g h i
1 2 3

关系运算符模式
这个模式下 pattern 为关系运算符表达式,处理每一行记录时,表达式为真,则执行紧跟其后的 action。

$ echo -e "a b c\nd e f\ng h i" | awk 'NR==2 {print $0}'
d e f

其他支持的关系运算符:

正则表达式模式 /…/
当在 awk 命令中使用正则表达式模式时,使用到的正则用法属于”扩展正则”。

$ echo -e "a b c\nd e f\ng h i" | awk '/^d/ {print $0}'
d e f

行范围模式 /re1/,/re2/
从被正则1匹配到的行开始,到被正则2匹配到的行结束。

$ echo -e "a b c\nd e f\ng h i" | awk '/d/,/i/ {print $0}'
d e f
g h i

当然也可用通过关系表达式模式来完成行范围匹配的效果。

$ echo -e "a b c\nd e f\ng h i" | awk 'NR>=2 && NR<=3 {print $0}'
d e f
g h i

sed

sed (stream editor for filtering and transforming text) 本质是一个流编辑器,用来过滤和修改文本。

用法

sed [OPTION]... {script-only-if-no-other-script} [input-file]

# 可简单理解为 sed [OPTION] {script} [input-file]
# 其中 {script} 是 pattern + command 
# input-file 也可以是标准输入

sed 常被用来搜索和替换文本,如:

$ seq 11 12 | sed '1 s/1/2/'
21
12

s 前的 1 是一个用于匹配的表达式 pattern,s 是一个替换文本内容的 command (可以理解为一个动作,官方文档称为 command),s 后面的表达式是 command s 的规则写法,意思为将每一行匹配到的第一个 1 替换为 2。
结合 pattern 为1 ,所以整个命令的意思是将第一行匹配到的 1 替换为 2。
这个命令可能初看不太好理解,等你看完后面介绍的 pattern 和 command 后再回过头来理解它就很轻松了。

pattern

行数匹配:

# 这里的 command `a\` 代表在 pattern 匹配到的行后追加新行的意思
# 在第一行后追加新的一行为字符串 newline
$ seq 11 12 | sed '1 a\newline'
11
newline
12

# 在第2~3行后追加新的一行为字符串 newline
$ seq 10 12 | sed '2,3 a\newline'
10
11
newline
12
newline

正则匹配:/re/ 在 // 中使用正则表示式作为 pattern

# 因为在第3行匹配到了 2 ,所以在第三行后增加了 newline 字符串。
$ seq 10 13 | sed '/2/ a\newline'
10
11
12
newline
13

正则区间匹配:/re1/,/re2/

$ seq 10 13 | sed '/12/,/13/ a\newline'
10
11
12
newline
13
newline

command

s
s 是最常用的一个 command,官方文档也将它与其他 command 单独分开,可见起重要和实用性。它的作用是可以通过 regexp 中的正则表达式匹配文本中的内容,将其修改为replacement 中的内容,也就是一个替换过程。flags 可简单理解为替换的形式。

# 用法
s/regexp/replacement/flags

# 符号 / 可以由其他符号代替,只要它们互相呼应出现即可。
# 即可以用 # 或其他符号代替如: s#regexp#replacement#flags 

这里介绍 command s 的2个常用用法

$ seq 100 102 | sed 's#0#2#'
120
121
122

# 加上 flags “g” 代表没行不止匹配 1 次,如果 flags 为数字 n 则代表替换第 n 次匹配。
$ seq 100 102 | sed 's#0#2#g'
122
121
122

使用扩展正则进行分组引用替换

# 使用 \1 , \2代表第一个和第二个正则分组,用来分别取出 161~163 的第2列和第3列。
# 由于使用 () 的分组正则属于扩展正则表达式,所以需要增加 -E 选项来开启扩展正则的支持。
$ seq 161 163 | sed -E 's#.(.)(.)#\1#'
6
6
6

$ seq 161 163 | sed -E 's#.(.)(.)#\2#'
1
2
3

其他常用 command

command 含义
a\ 在行后追加,之前 pattern 的例子都是用的它
c\ 行替换
d 删除
p 打印,常配合 -n(静默模式) 使用
# 第二行替换为 aaa
$ seq 3 | sed '2 c\aaa'
1
aaa
3

# 第二行删除
$ seq 3 | sed '2 d'
1
3
# 删除第二行到最后一行
$ seq 3 | sed '2,$ d'
1

# 打印第2行
$ seq 3 | sed '2 p'
1
2
2
3
# 只打印第2行
$ seq 3 | sed -n '2 p'
2

~~本文完~~

Tips:本站使用 Disqus 评论,被墙访客请科学上网后点击加载。