awk、sed、grep综述:
grep 更适合单纯的查找或匹配文本
sed 更适合编辑匹配到的文本
awk 更适合格式化文本,对文本进行较复杂格式处理
1.Linux sed 命令
Linux sed命令是利用script来处理文本文件。
sed可依照script的指令,来处理、编辑文本文件。
sed主要用来:
自动编辑一个或多个文件;
简化对文件的反复操作;
编写转换程序等。
语法
sed [-hnV][-e
参数说明
-e
-f
-h或--help 显示帮助
-n或--quit或--silent 仅显示script处理后的结果
-V或--version 显示版本信息
动作说明:
a:新增。a后面可以接字符串,而这些字符串会在新的一行出现(当前行的下一行)
c:取代。c的后面可以接字符串,这些字符串可以取代n1,n2之间的行
d:删除。d的后面一般不接其他东西
i:插入。i的后面可以接字符串,而这些字符串会在新的一行出现(当前行的上一行)
p:打印。亦即将某个选择的数据打印出来。通常p会与参数sed -n一起运行
s:取代。可以直接进行取代的工作。通常这个s的动作可以搭配正规表示法。例如1,20s/old/new/g。
实例
在testfile文件的第四行后添加一行,并将结果输出到标准输出,在命令行提示符下输入如下命令:
sed -e 4a\newLine testfile
首先查看testfile中的内容如下:
$ cat testfile
第一行
第二行
第三行
第四行
第五行
运行sed命令,输出结果如下:
第一行
第二行
第三行
第四行
newline
第五行
以行为单位的新增/删除
将 textfile 的内容列出并且列出行号,同时,请将第2~5行删除:
$ nl testfile | sed '2,5d'
1 第一行
只删除第二行:
$ nl testfile | sed '2d'
1 第一行
3 第三行
4 第四行
5 第五行
删除从第三行开始的所有行:
$ nl testfile | sed '3,$d'
1 第一行
2 第二行
在第二行后(即加在第三行)加上[drink tea?]字样!
$ nl testfile | sed '2a drink tea'
1 第一行
2 第二行
drink tea
3 第三行
4 第四行
5 第五行
如果是要在第二行前:
$ nl testfile | sed '2i drink tea'
如果是要增加两行以上,比如在第二行后面加入两行字『drink tea or ...』与『drink beer?』:
$ nl testfile | sed '2a drink tea or ...\
> drink beer ?'
1 第一行
2 第二行
drink tea or ...
drink beer ?
3 第三行
4 第四行
5 第五行
每个行之间都必须要以反斜杠\来进行新行的添加。所以上面的例子中,我们可以发现在第一行的最后面就有\的存在。
以行为单位的替换与显示
例如,将第2-5行的内容取代成为『No 2-5 number』:
$ nl testfile | sed '2,5c No 2-5 number'
1 第一行
No 2-5 number
透过这个方法,我们就能将数据整行取代了。
仅列出testfile文件内的第2-4行:
$ nl testfile | sed -n '2,4p'
2 第二行
3 第三行
4 第四行
可以透过这个sed的以行为单位的显示功能,就能够将某一个文件内的某些行号选择出来显示。
数据的搜寻并显示
搜索testfile有"四"关键字的行
$ nl testfile | sed '/四/p'
1 第一行
2 第二行
3 第三行
4 第四行
4 第四行
5 第五行
可见找到匹配行后,除了输出所有行,还会再次打印出此行。
使用-n的时候只会打印匹配的行。
$ nl testfile | sed -n '/四/p'
4 第四行
数据的搜寻并删除
删除testfile所有包含'四'的行,其他行输出:
$ nl testfile | sed '/四/d'
1 第一行
2 第二行
3 第三行
5 第五行
数据的搜寻并执行命令
搜索testfile,找到包含'四'的行,执行后面花括号中的一组命令,每个命令之间用分号分隔,这里把'行'替换为'列',再输出这行:
$ nl testfile | sed -n '/四/{s/行/列/;p;q}'
4 第四列
最后的q是退出。
数据的搜寻并替换
除了整行的处理模式之外,sed还可以用行为单位进行部分数据的搜寻并取代。基本上sed的搜寻与替代的与vi相当的类似,例如:
sed 's/要被取代的字符串/新的字符串/g'
利用/sbin/ifconfig查询IP:
删除IP前面部分的内容:
$ /sbin/ifconfig eth2 | grep 'inet addr' | sed 's/^.*addr://g'
192.168.80.100 Bcast:192.168.80.255 Mask:255.255.255.0
下面删除后续部分内容:
$ /sbin/ifconfig eth2 | grep 'inet addr' | sed 's/^.*addr://g' | sed 's/Bcast.*$//'
192.168.80.100
多点编辑
一条sed命令,删除testfile第三行到末尾的行,并将"行"替换为"列"
$ nl testfile | sed -e '3,$d' | sed -e 's/行/列/'
1 第一列
2 第二列
直接修改文件内容(危险动作)
sed可以直接修改文件的内容,不必使用管道命令或数据量重导向。不过,由于这个动作会直接修改到原始的文件,所以请千万不要随便拿系统配置来测试。
利用sed将testfile内每一行的“行”修改为“列”:
$ sed -i 's/行/列/g' testfile
$cat testfile
第一列
第二列
第三列
第四列
第五列
利用sed直接在testfile最后一行加入"第六行":
$ sed -i '$a 第六行' testfile
$ cat testfile
第一列
第二列
第三列
第四列
第五列
第六行
由于$代表的是最后一行,而a的动作是新增,因此会增加在文件最后。
sed的-i选项可以直接修改文件内容,这功能非常有帮助。举例来说,如果你有一个100万行的文件,你要在第100行加某些文字,此时使用vim可能会疯掉,因为文件太大了。此时可以使用sed直接修改/取代。
2.Linux grep 命令
Linux grep命令用于查找文件里符合条件的字符串。
grep指令用于查找内容包含指定的范本样式的文件,如果发现某文件的内容符合所指定的范本样式,预设grep指令会把含有范本样式的那一列显示出来。若不指定任何文件名称,或是所给予的文件名为"-",则grep指令会从标准输入设备读取数据。
语法
grep [-abcEFGhHilLnqrsvVwxy][-A<显示列数>][-B<显示列数>][-C<显示列数>][-d<进行动作>][-e<范本样式>][-f<范本文件>][--help][范本样式][文件或目录...]
参数:
-a 或 --text:不要忽略二进制的数据。
-A<显示行数> 或 --after-context=<显示行数>:除了显示符合范本样式的那一列之外,并显示改行之后的内容。
-b 或 --byte-offset:在显示符合样式的那一行之前,标示出该行第一个字符的编号。
-B<显示行数> 或 --before-context=<显示行数>:除了显示符合样式的那一行之外,并显示该行之前的内容。
-c 或 --count:计算符合样式的列数。
-C<显示行数> 或 --contest=<显示行数> 或 -<显示行数>:除了显示符合样式的那一行之外,并显示该行之前后的内容。
-d<动作> 或 --directories=<动作>:当指定要查找的是目录而非文件时,必须使用这项参数,否则grep指令将回报信息并停止动作。
-e<范本样式> 或 --regexp=<范本样式>:指定字符串作为查找文本内容的样式。
-E 或 -extended-regexp:将样式为延伸的普通表示法来使用。
-f<规则文件> 或 --file=<规则文件>:指定规则文件,其内容含有一个或多个规则样式,让grep查找符合规则条件的文件内容,格式为每行一个规则样式。
-F 或 --fixed-regexp:将样式视为固定字符串的列表。
-G 或 --basic-regexp:将样式视为普通的表示法来使用。
-h 或 -no-filename:在显示符合样式的那一行之前,不标示该行所属的文件名称。
-H 或 --with-filename:在显示符合样式的那一行之前,标示该行所属的文件名称。
-i 或 --ignore-case:忽略字符大小写的差别。
-I 或 --file-with-matches:列出文件内容符合指定的样式的文件名称。
-L 或 --file-without-match:列出文件内容不符合指定的样式的文件名称。
-n 或 --line-number:在显示符合样式的那一行之前,标示出该行的列数编号。
-q 或 --quiet 或 --silent:不显示任何信息。
-r 或 -recursive:此参数的效果和指定-d recurse参数相同。
-s 或 --no-messages:不显示错误信息。
-v 或 --revert-match:显示不包含匹配文本的所有行。
-V 或 --version:显示版本信息。
-w 或 --word-regexp:只显示全字符合的列。
`-x 或 --line-regexp':只显示全列符合的列。
-y:此参数的效果和指定-i参数相同。
实例:
1.在当前目录中,查找后缀有file字样的文件中包含test字符串的文件,并打印出该字符串的行。此时,可以使用如下命令:
grep test *file
结果如下:
$ grep test *file
This is a test!
$ cat test testfile
第一列
第二列
第三列
第四列
第五列
第六行
This is a test!
2.以递归方式查找符合条件的文件。例如,查找指定目录及其子目录(如果存在子目录的话)下所有文件中包含字符串"conf"的文件,并打印出该字符串所在行的内容,使用的命令为:
$ grep -r conf /etc/acpi
/etc/acpi/events/power.conf:# ACPID config to power down machine if powerbutton is pressed, but only if
3.反向查找。前面各个例子是查找并打印出符合条件的行,通过-v参数可以打印出不符合条件行的内容。
例如,查找当前目录中,文件名中包含test的文件中不包含test的行,此时,使用的命令为:
$ grep -v test *test*
test1.sh:#!/bin/bash
test1.sh:c1="shell"
test2.sh:#!/bin/bash
test2.sh:#或者使用以下包含文件代码
test2.sh:echo "zkn在学习$c1"
testfile:第一列
testfile:第二列
testfile:第三列
testfile:第四列
testfile:第五列
testfile:第六行
3.Linux awk 命令
awk是一种处理文本文件的语言,是一个强大的文本分析工具。
之所以叫awk是因为其取了三位创始人Alfred Aho、Peter Weinberger和Barian Kernighan的Family Name的首字母。
语法
awk [选项参数] 'script' var=value file(s)
或
awk [选项参数] -f scriptfile var=value file(s)
选项参数说明:
-F fs 或 --file-separator fs 指定输入文件拆分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
-v var=value 或 --asign var=value 赋值一个用户定义变量
-f scripfile 或 --file scriptfile 从脚本文件中读取awk命令。
-mf nnn 和 -mr nnn 对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
-W compat 或 --compat ; -W traditional --traditional在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。
-W copyleft 或 --copyleft ; -W copyright 或 --copyright 打印简短的版权信息。
-W help 或 --help ; -W usage 或 --usage 打印全部awk选项和每个选项的简短说明。
-W lint 或 --lint 打印不能向传统unix平台移植的结构的警告。
-W lint-old 或 --lint-old 打印关于不能向传统unix平台移植的结构的警告。
-W posix 打开兼容模式。但有以下限制:不识别/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替和=;fflush无效。
-W re-interval 或 --re-inerval 允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha]]。
-W source program-text 或 --source program-text 使用program-text作为源代码,可与-f命令混用。
-W version 或 --version 打印bug报告信息的版本。
基本用法
log.txt文本内容如下:
2 this is a test
3 Are you like awk
This's a test
10 There are orange,apple,mongo
用法一:
awk '{[pattern] action}' {filenames} #行匹配语句 awk '' 只能用单引号
实例:
# 每行按空格或TAB分割,输出文本中的1/4项
$ awk '{print $1,$4}' log.txt
2 a
3 like
This's
10 orange,apple,mongo
或
$ awk '{printf "%-8s %-10s\n",$1,$4}' log.txt
2 a
3 like
This's
10 orange,apple,mongo
用法二:
awk -F #-F相当于内置变量F5,指定分割字符
实例:
### 使用","分割
$ awk -F: '{print $1,$2}' log.txt
2 this is a test
3 Are you like awk
This's a test
10 There are orange,apple,mongo
### 或者使用內建变量
$ awk 'GEGIN{FS=","}{print $1,$2}' log.txt
2 this
3 Are
This's a
10 There
### 使用多个分隔符。先使用空格分割,然后对分割结果再使用","分割
$ awk -F '[ ,]' '{print $1,$3,$5}' log.txt
2 is test
3 you awk
This's test
10 are apple
用法三:
awk -v #设置变量
实例:
$ awk -va=1 '{print $1,$1+a}' log.txt
2 3
3 4
This's 1
10 11
$ awk -va=1 -vb=s '{print $1,$1+a,$1b}' log.txt
2 3 2s
3 4 3s
This's 1 This'ss
10 11 10s
用法四:
awk -f {awk脚本} {文件名}
实例:
$ awk -f cal.awk log.txt
运算符
运算符
描述
= += -= *= /= %= ^= **=
赋值
?:
C条件表达式
||
逻辑或
&&
逻辑与
~ ~!
匹配正则表达式和不匹配正则表达式
< <= > >= != ==
关系运算符
空格
连接
+ -
加和减
* / %
乘、除和求余
+ - !
一元加、减和逻辑非
^ ***
求幂
++ --
增加或减少,作为前缀或后缀
$
字段引用
in
数组成员
过滤第一列大于2的行:
$ awk '$1>2' log.txt
3 Are you like awk
This's a test
10 There are orange,apple,mongo
获取第一列等于2的行:
$ awk '$1==2' log.txt
2 this is a test
获取第一列大于2并且第二列等于'Are'的行:
$ awk '$1>2 && $2=="Are" ' log.txt
3 Are you like awk
內建变量
变量
描述
$n
当前记录的第n个字段,字段间由FS分隔
$0
完整的输入记录
ARGC
命令行参数的数目
ARGIND
命令行中当前文件的位置(从0开始算)
ARGV
包含命令行参数的数组
CONVFMT
数字转换格式(默认%.6g)ENVIRON环境变量关联数组
ERROR
最后一个系统错误的描述
FIELDWIDTHS
字段宽度列表(用空格键分隔)
FILENAME
当前文件名
FNR
个文件分别计数的行数
FS
字段分隔符(默认是任何空格)
IGNORECASE
如果为真,则进行忽略大小写的匹配
NF
一条记录的字段的数目
NR
已经读出的记录数,就是行号,从1开始
OFMT
数字的输出格式(默认是%.6g)
OFS
输出记录分隔符(输出换行符),输出时用指定的符号代替换行符
ORS
输出记录分隔符(默认是一个换行符)
RLENGTH
由match函数所匹配的字符串的长度
RS
记录分隔符(默认是一个换行符)
RSTART
有match函数所匹配的字符串的第一个位置
SUBSEP
数组下标分隔符(默认值是/034)
使用正则字符串匹配
输出第二列包含"th"的行,并打印第二列和第四列
$ awk '$2 ~ /th/ {print $2,$4}' log.txt
this a
~表示模式开始,//中是模式
输出包含"re"的行
$ awk '/re/' log.txt
3 Are you like awk
10 There are orange,apple,mongo
忽略大小写
$ awk 'BEGIN{IGNORECASE=1} /this/' log.txt #大写和小写的this均匹配出来了
2 this is a test
This's a test
模式取反
$ awk '$2 !~ /th/ {print $2,$4}' log.txt
Are like
a
There orange,apple,mongo
$ awk '!/th/ {print $2,$4}' log.txt
Are like
a
There orange,apple,mongo
awk脚本
关于awk脚本,我们需要注意两个关键词BEGIN和END。
BEGIN{这里面放的是执行前的语句}
END{这里面放的是处理完所有的行后要执行的语句}
{这里面放的是处理每一行时要执行的语句}
假设有这么一个文件(学生成绩表):
$ cat score.txt
Marry 2143 78 84 77
Jack 2321 66 78 45
Tom 2122 48 77 71
Mike 2537 87 97 95
Bob 2415 40 57 62
我们的awk脚本如下:
$ cat cal.awk
#!/bin/awk -f
#运行前
BEGIN {
math = 0
english = 0
computer = 0
printf "NAME NO. MATH
ENGLISH COMPUTER TOTAL\n"
}
#运行中
{
math+=$3
english+=$4
computer+=$5
printf "%-6s %-6s %4d %8d %8d %8d\n",$1,$2,$3,$4,$5,$3+$4+$5
}
#运行后
END{
printf "TOTAL:%10d %8d %8d \n",math,english,computer
printf "AVERAGE:%10.2f %8.2f %8.2f\n",math/NR,english/NR,computer/NR
}
下面看执行结果:
$ awk -f cal.awk score.txt
NAME NO. MATH ENGLISH COMPUTER TOTAL
Marry 2143 78 84 77 239
Jack 2321 66 78 45 189
Tom 2122 48 77 71 196
Mike 2537 87 97 95 279
Bob 2415 40 57 62 159
TOTAL: 319 393 350
AVERAGE: 63.80 78.60 70.00
另外一些实例
awk的hello world程序为:
BEGIN { print "Hello,World!"}
计算文件大小:
$ ls -l *.txt | awk '{sum+=$5} END {print sum}'
192
从文件中找出长度大于20的行:
$ awk 'length>20' log.txt
10 There are orange,apple,mongo
打印九九乘法口诀:
$ seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s",i,NR,i*NR,i==NR?"\n":"\t")}'
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81