grep
指定的输入文件中搜索包含与给定模式匹配的行。一般用来搜索文件中的指定内容,和搜索包含指定内容的文件。
命令格式
grep [option...] [patterns] [file...]
一般模式需要用引号括起来。
常用选项
选项 | 含义 |
---|---|
-i | 忽略大小写 |
-c | 只输出匹配行的数量 |
-n | 显示行号 |
-r | 递归搜索 |
-E | 支持拓展正则表达式 |
-w | 匹配整个单词 |
-l | 只列出匹配的文件名 |
-F | 不支持正则,按字符串字面意思进行匹配 |
举例:
现在有文件file.txt,内容如下
#test.txt
abc
ABC
bcd
acea
helloworld
^b
搜索包含a内容的行
grep a test.txt
结果:
abc
acea
搜索以a结尾的内容
grep "a$" test.txt
结果:
acea
-i 忽略大小写
grep -i "a" test.txt
结果:
abc
ABC
acea
-c 只输出匹配行的数量
grep -c "a" test.txt
结果:
2
grep -c "" test.txt
结果:
6
-n 显示行号
grep -n "a" test.txt
结果:
1:abc
4:acea
-r 递归搜索,当递归地读取和处理目录中的所有文件时需要加上-r, 在当前目录复制一个test1.txt文件,通过递归搜索包含hello的文件
grep -r hello .
结果:
./test1.txt:helloworld
./test.txt:helloworld
-l 只列出匹配的文件名
grep -lr 'a' .
结果:
./test1.txt
./test.txt
-w 匹配整个单词
# 不加-w时会匹配到hello
grep hello test.txt
结果:
helloworld
#全词匹配 -w
grep -w hello test.txt
结果为空
-F 不支持正则,当匹配的内容为正则表达式的符号时,需要加-F来表示字符串字面意思进行匹配
# 查找^b字符,不加-F,默认会以正则字符去匹配,查找以b开头的内容
grep ^b test.txt
结果:
bcd
# 加上-F
grep -F ^b test.txt
结果:
^b
-E 支持拓展正则表达式,当使用正则表达式匹配时需要加-E
grep -E '(bc)' test.txt
结果:
abc
bcd
sed
sed(stream editor)流编辑器,对文件逐行处理。通常用来过滤,替换,修改文本。
命令格式
sed OPTIONS... [SCRIPT] [INPUTFILE...]
常用选项 OPTIONS
选项 | 含义 |
---|---|
-n | -n抑制默认的每行输出,一般会和p命令一起使用 |
-f | 加载存放动作的文件 |
-r | 支持拓展正则 |
-i | 直接修改文件 |
sed命令
这里的sed命令就是上面的[SCRIPT]部分。
语法
[addr]X[options]
#X是单字母sed命令
[addr]是可选行地址,如果指定了[addr],命令X将只在匹配的行上执行。
[options]是某些sed命令的额外选项
常用命令
命令 | 说明 |
---|---|
p | 打印处理后的内容 |
a text | 在匹配行后插入指定内容,注意a后面有个空格 |
i text | 在匹配行前新增指定内容,注意i后面有个空格 |
r filename | 读取文件filename的内容,然后插入匹配行后 |
w | filename 将匹配内容写入文件filename中 |
d | 删除匹配的行 |
s/regexp/replacement/[flags] | 将匹配的行中匹配regexp的部分替换为replacement,flags:g全替换,i忽略大小写,m匹配多行 |
地址选择
表达式 | 说明 |
---|---|
number | 匹配第number行 |
$ | 匹配最后一行 |
first~step | 匹配从first开始的每step行,例如1~ 2表示选择奇数行,0~2表示选择偶数行 |
m,n | 匹配从第m到第n行 |
/regexp/ | 匹配能匹配regexp的行 |
继续以上面的文本内容为例:
#test.txt
abc
ABC
bcd
acea
helloworld
^b
-n抑制默认的每行输出,一般会和p命令一起使用打印奇数行内容
sed -n '1~2p' test.txt # 如果不加-n,那么sed会每出来一行就会输出一次。
结果:
abc
bcd
helloworld
s/regexp/replacement/[flags] 替换,flags默认为g全部替换,i忽略大小写,m匹配多行
# 将test.txt中的abc替换成cba
sed 's/abc/cba/' test.txt
结果:
cba
ABC
bcd
acea
helloworld
^b
# 加i忽略大小写
sed 's/abc/cba/i' test.txt
结果:
cba
cba
bcd
acea
helloworld
^b
此时test.txt文件内容时没有被修改的,只是在读取后进行了替换并输出。如果想修改文件内容需要加-i。
-i 直接修改文件
sed -i 's/abc/cba/i' test.txt
# 保险起见,修改的同时备份一份源文件,可以在i后面加后缀名
sed -ibak 's/abc/cba/i' test.txt
a text 在匹配行后插入指定内容,注意a后面有个空格
i text 在匹配行前新增指定内容,注意i后面有个空格
sed 'a ccc' test.txt # 在每一行的后面插入abc
sed '1a ccc' test.txt # 在第一行的后面插入abc
sed '/^B/a abc' test.txt # 在以B开头的行后面插入abc
sed '/^B/i abc' test.txt # 在以B开头的行前面插入abc
r filename 读取文件filename的内容,然后插入匹配行后
举例:
有文件text.txt,text1.txt内容如下
# test.txt
hello
world
#text1.txt
a
b
c
# 将test.txt中的内容插入到test1.txt的第1行后面
sed '1 r test.txt' test1.txt
结果:
a
hello
world
b
c
w filename 将匹配内容写入文件filename中
继续以上面的文件内容为例:
#将test.txt中的第一行内容写到test1.txt中
sed '1w test1' test1.txt
d 删除匹配的行
#删除test.txt的第一行
sed '1d' test.txt
# 如果真正删除源文件内容加-i即可
sed -i '1d' test.txt
通过N参数合并行
举例:
test.txt文件内容如下
hi!
hello
world
将hello world合并成1行
sed '2{N;s/\n//;}' test.txt
# 在第二行先把换行替换为空然后再通过N参数把下一行合并进来
hi!
helloworld
awk
awk是一种解释型编程语言,类似于python。一般用于对数据文件的处理。
命令格式
awk 'BEGIN{commands}pattern{commands}END{commands}' file;
格式 | 说明 |
---|---|
BEGIN{} | 处理数据之前执行 |
pattern | 匹配模式 |
{commands} | 处理的命令,必须使用大括号包含 |
END{} | 处理数据之后执行 |
匹配模式
匹配模式用来筛选要处理的数据。awk中的模式有如下几种:
正则表达式
要使用斜杠包裹起来:/regexp/
普通表达式
一般是一个比较表达式
例如:
$1 == "on" # 第一个字段等于on
BEGIN END
为awk程序提供启动或清理操作的特殊模式。
BEGIN在处理前执行
END在处理后执行
内置变量
内置变量 | 含义 |
---|---|
$0 | 整行内容 |
$ 1,$n | 当前行的第1至n个字段 |
NF | (Number Field) 当前行字段数,$NF就是最后一个字段 |
NR | (Number Row) 当前行行号,从1开始 |
FS | (Field Separator) 输入字段分割符,默认为空格或tab键 |
RS | (Row Separator) 输入行分割符,默认为回车符 |
OFS | (Output Field Separator) 输出字段分割符,默认为空格 |
ORS | (Output Row Separator) 输出行分割符,默认为回车符 |
输出命令
print item1, item2, ...
打印item1,item2,用空格连接,如果省略了逗号,中间的空格会被省略
printf format, item1,time2,...
格式化输出,c语言风格。
举例:
有1.txt文件内容如下:
a 1-1 22
b 3-3 44
c 5-5 66
d 7-7 88
1.$n筛选当前行的第一个字段:
awk '{print $1}' 1.txt # 默认为空格或tab键分割,$2就是每行的第2个字段,以此类推
结果:
a
b
c
d
2.$ 1,$n筛选当前行的第1到2个字段:
awk '{print $1,$2}' 1.txt
结果:
a 1-1
b 3-3
c 5-5
d 7-7
3.NF(Number Field) 当前行字段数
awk '{print NF}' 1.txt
结果:
3
3
3
3
# 获取最后一行可以通过$NF
awk '{print $NF}' 1.txt
结果:
22
44
66
88
4.NR,行号
awk '{print NR}' 1.txt
结果:
1
2
3
4
5.FS(Row Separator) 指定字段分割符,默认为空格或tab键
当有些文件内容并不是以空格或tab键分割时,在处理数据之前可以通过FS指定分割符。
如下以-号分割输出1.txt文件内容的第一个字段
awk 'BEGIN{FS="-"} {print $1}' 1.txt
结果:
a 1
b 3
c 5
d 7
6.RS(Row Separator) 指定行分割符,默认为回车符
修改1.txt内容如下
a 1-1 22t3
b 3-3 44t4
c 5-5 66t5
d 7-7 88t6
# 通过RS指定以t为换行符,输出全部行
awk 'BEGIN{RS="t"} {print $0}' 1.txt
结果:
a 1-1 22
3
b 3-3 44
4
c 5-5 66
5
d 7-7 88
6
7.OFS(Output Field Separator) 输出字段分割符,默认为空格
如下输出第一个第二个字段以~符链接
awk 'BEGIN{OFS="~"}{print $1,$2}' 1.txt
结果:
a~1-1
b~3-3
c~5-5
d~7-7
// An highlighted block
var foo = 'bar';
// An highlighted block
var foo = 'bar';
简单案例
数据内容
文件mail-list包含如下内容:
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
Bill 555-1675 bill.drowning@hotmail.com A
Broderick 555-0542 broderick.aliquotiens@yahoo.com R
Camilla 555-2912 camilla.infusarum@skynet.be R
Fabius 555-1234 fabius.undevicesimus@ucb.edu F
Julie 555-6699 julie.perscrutabor@skeeve.com F
Martin 555-6480 martin.codicibus@hotmail.com A
Samuel 555-3430 samuel.lanceolis@shu.edu A
Jean-Paul 555-2127 jeanpaul.campanorum@nyu.edu R
这是一个邮箱列表,每条记录包含姓名,电话号码,邮箱地址以及一个表示关系的字母,F表示朋友,A表示认识的人,R表示亲戚。
文件inventory-shipped包含如下内容:
Jan 13 25 15 115
Feb 15 32 24 226
Mar 15 24 34 228
Apr 31 52 63 420
May 16 34 29 208
Jun 31 42 75 492
Jul 24 34 67 436
Aug 15 34 47 316
Sep 13 55 37 277
Oct 29 54 68 525
Nov 20 87 82 577
Dec 17 35 61 401
Jan 21 36 64 620
Feb 26 58 80 652
Mar 24 75 70 495
Apr 21 70 74 514
#这是一个发货清单,每条记录包含月份,以及A,B,C,D四种商品的发货数量。这里有16条记录,包含去年12月以及今年4个月的发货记录。使用一个空行分隔两年的数据。
1.筛选记录中包含li的邮件联系人
awk '/li/ { print $0 }' mail-list # { print $0 }可以省略,模式就是这个action
2.筛选字符数大于8的记录
awk 'length($0) > 8' mail-list
3.最长记录的字符数
awk '{ if (length($0) > max) max = length($0) } END { print max }' mail-list # 通过变量max记录,最后再END语句中输出
4.打印至少包含一个字段的行
awk 'NF > 0' data
5.打印7个0-100之间的随机数
awk 'BEGIN { for (i = 1; i <= 7; i++) print int(101 * rand()) }'
6.打印文件文件夹的总字节数
ls -l . | awk '{ x += $5 } END { print "total bytes: " x }'
7.打印文件文件夹的总KB数
ls -l files | awk '{ x += $5 } END { print "total K-bytes:", x / 1024 }'
8.打印所有用户登录名的排序列表
awk -F: '{ print $1 }' /etc/passwd | sort
9.计算文件中的行数
awk 'END { print NR }' data
10.打印数据文件中的偶数行
awk 'NR % 2 == 0' data
11.打印第一个字段和最后一个字段
awk '/li/ { print $1, $NF }' mail-list
12.格式化输出第一第二个字段
awk '{ printf "%-10s %s\n", $1, $2 }' mail-list
13.统计今年和去年的A商品的发货总数
#思路,在碰到换行符之前使用lastyear累加,碰到换行符之后使用currentyear累加
awk 'BEGIN{ l=1 }{ if(l==1) lastyear+=$2; else currentyear+=$2 } { if(NF==0) l=0} END{ printf "lastyear: %s, currentyear: %s\n", lastyear, currentyear }' inventory-shipped
14.统计去年A商品的月发货平均数
awk 'BEGIN{ l=1 } { if(l==1) lastyear+=$2 } {if (NF==0) l=0 } END{ printf "lastyear A average:%.2f\n", lastyear / 12 }' inventory-shipped
15.指定分隔符
awk 'BEGIN{ FS="-" } {print $1}' mail-list