文章目录
linux三剑客grep、sed、awk
正则表达式
正则表达式是定义的模式的模板,linux用它来匹配数据。如果数据匹配模式,则会接受进一步的处理。否则,不会进行处理。
正则表达式有两种引擎,引擎用来解释正则表达式和执行文本匹配。
- BRE。基础。
- ERE。拓展,包含更多的模式。
在linux中,grep、awk、sed会使用正则表达式来匹配数据。
特殊字符
正则表达式有一些特殊字符有着特殊的含义,下面以sed工具进行说明。
> echo "book store" | sed -n '/^book/p' #匹配book开头的行,-n表示用p代替命令输出,否则有两行数据,p表示输出匹配的模式。
.
==.==表示任意一个字符。
> echo "book store" | sed -n '/./p '
> echo "book store" | sed -n '/.o/p' #使用一个字符串进行匹配,字符串的第一个字符随意,第二个一定是o
*
表示前面的字符或者字符组出现了0次或多次,==.*==两者连用 表任意多个字符。注意,这里的*与linux命令行中的*不一样!
> echo "book store" | sed -n '/o\*/' #匹配0个或多个o字符
> echo "book store" | sed -n '/.\*' #使用任意字符串进行匹配,即所有数据都能匹配
[]
字符组。若数据中出现该字符组的任一字符,则数据匹配该模式。例如[a,b,c]表数据中若含有abc中的任意一个都算匹配。
可以使用连续的区间而不用一个个的指定字符。如,[a-z],[0-9]。也可使用不连续的区间,如[1-35-6]表示区间[1-3]和[5-6]。另外,可以搭配==^==使字符组反转,例如[^1-2]表示除1或者2之外的字符。
> echo "123" | sed -n '/[4-6]/p' #匹配含有4,5,6的行。这一行不匹配。
> echo "4" | sed -n '/\[2-3][5-6]/p' #匹配含有2,3,5,6的行。这一行不匹配。
> echo "3" | sed -n '/\[^1-2]/p' #匹配不含1或2的行。
此外,正则表达式有一些特殊的字符组。
特殊字符组 | 说明 |
---|---|
[[:alpha:]] | 英文字母,同[a-zA-Z] |
[[:alnum:]] | 任意字母和数字,同[0-9]或[a-z]或[A-Z] |
[[:blank:]] | 空格或者制表符 |
[[:digit:]] | 数字 |
[[:lower:]] | 小写英文字母 |
[[:upper:]] | 大写英文字母 |
[[:print:]] | 可打印字符 |
[[:punct:]] | 标点符号 |
[[:space:]] | 任意空白字符,包括:空格、制表符、NL、FF、VT和CR |
^
锚定符,表示行首。也可出现在==[]中,是[]==表示排除字符组。如,[^a]除a以外的字符。
echo “num1: hello” | sed -n ‘/^num1/p’ #匹配以num1开头的行
$
锚定符,表示行尾。与 ^ 结合得到 ^$,表示空行。在使用行号寻址的时,表示最后一行。
echo “hello” | sed -n ‘/^$/p’ #匹配空行
echo “what a big 3” | sed -n ‘/3$/p’ #匹配以3结尾的行
{}
花括号用于限定前面字符或者字符组出现的次数。有以下格式:
- {n}。精确到n个。
- {n,}。至少n个。
- {n,m}。至少n个,至多m个。
使用花括号,需要ERE模式的引擎。若在sed中使用,需要转义。
echo “this an book!” | sed -n ‘/o\{3\}/p’ #不会匹配,因为没有连续的3个o
echo “this an book!” | sed -n ‘/o\{2\}/p’ #匹配,含有连续的2个o
|
表示逻辑或,模式1==|== 模式2,表示若数据含有两个模式中的任意一个模式,就算匹配。在sed中使用需要转义
echo “you have a apple” | sed -n ‘/apple\|banana/p’ #管道符需要转义,匹配apple或者banana
+
前面字符或者字符组出现1次以上。注意转义。
echo “abc” | sed -n ‘/a\+/p’ #a出现一次,匹配
echo “bc” | sed -n ‘/a\+/p’ #a没有出现,不算匹配
?
前面字符或者字符组出现0次1次。注意转义。
echo “abc” | sed -n ‘/a\?/p’ #a出现一次,匹配
echo “bc” | sed -n ‘/a\?/p’ #a没有出现,也算匹配
()
==()==用于给表达式分组。注意转义。
echo “a = 1” | sed -n ‘/\(a\|b\) = /p’ #匹配
echo “b = 1” | sed -n ‘/\(a\|b\) = /p’ #匹配
echo “c = 1” | sed -n ‘/\(a\|b\) = /p’ #不匹配
grep
sed
sed称作流编辑器,它主要做了:
- 从输入中读取一行
- 根据所提供的模式匹配数据
- 根据命令修改数据
- 将新的数据写到stdout中。不管数据是否被修改,都会输出到标准输出。
sed命令的格式如下:
> sed options script file #options是选项;srcipt是命令,包好模式和命令;file是输入文件
以下是sed的一些常用的选项及其说明:
sed选项 | 说明 |
---|---|
-e script | 使用e指定多条命令 |
-f file | 使用f读取存放命令的文件 |
-n | 不输出数据,但可以使用命令p输出满足模式的数据 |
-i | 输出会写入源文件中 |
一般使用sed作为sed脚本文件的拓展名。
sed中的命令
寻址
sed支持两种寻址方式,使用文本模式寻址和使用行号寻址。可以在寻址后面加上==!==,对地址取反,让脚本作用于与该模式不匹配的行。
两种寻址方式的格式:
address command #对匹配的行执行一条指令
address { #对匹配的行执行多条指令
command1;
command2;、
command3;
}
在执行完一条命令或者一组命令后,会处理下一行。
使用行号寻址
> sed -n '1,5s/cat/dog/' data.txt #替换1到5行中的首个cat为dog
> sed -n '1,$s/cat/dog/' data.txt #替换所有行的首个cat为dog
使用文本模式寻址
> sed -n '/cat/s/cat/dog' data.txt #替换 含有cat的行 的首个cat为dog
使用==!==对地址取反
> echo "dog mouse" |sed -n '/dog/p' #会打印包含dog的行
> echo "dog mouse" | sed -n '/dog/!p' #不会打印包含dog的行,它会匹配不包含dog的行
执行多条指令
> sed -n '1,$
> {
> s/cat/dog/
> s/dog/mouse
>}' #对所有行执行多条指令
替换
替换命令 s/字符串/字符串/,会将满足模式中的行中一个字符串替换为另外一个字符串,默认只替换一次。为避免/和\造成的辨识不清楚,可以使用 ! 代替 /, 替换后,s!字符串!字符串!。
替换命令默认只替换第一个满足模式的字符串,可以使用替换标记修改替换的行为。替换标记使用方法如下:
> sed 's/dog/cat/替换标记' data.txt
替换标记如下:
- 数字。假设指定数字2,则替换满足条件的第2处字符串。
- g。替换所有满足条件的字符串。
- p。输出修改后的行。
- w。将输出保存到指定的文件中。
删除
删除命令d会删除所有满足模式的行。可以使用行号、文本模式指定要删除的行,此外,也可以使用两个模式来删除两个模式之间的行。
> sed '/dog/d' data.txt #删除含有dog的行
> sed '2d' data.txt #删除第二行
> sed '/dog/,/cat/' #删除dog和cat之间的所有行
插入和附加文本
插入命令i会在行前增加一个新行,附加命令a会在行后增加一个新行,字符串使用==\==指定。
使用格式如下:
> sed '[address] i \string' data.txt
> sed '[address] a \string' data.txt
如:
> sed '1 i\dog' data.txt #在第一行前插入dog
> sed '1 a\dog' data.txt #在第一行后插入dog
> sed '/cat/i\dog' data.txt #在有cat的行的前面插入dog
修改行
修改(change)命令c会修改它所匹配的行,使用==\== 指定修改后的字符串。命令c与命令s的区别在于,c会修改整行,而s只修改匹配的数据。
使用格式:
> sed '\dog\c/cat' data.txt #将含有dog的行整体修改为字符串cat
转换
转换命令y用于处理单个字符。通过给定两个大小相同的集合,命令y可以将一个集合中的字符映射为另一个集合中的字符。
使用格式:
> [address]y/字符集s/字符集d/ #替换s中的字符为d中字符
如:
> sed '1,$y/dg/ab/' data.txt #将满足模式的行中的d替换为a,将g替换为b
打印
可以使用三个指令用来打印数据。分别是:
- p。打印完整的行。
- =。打印行号,行号在行的上一行。
- l。打印行中数据,不可打印数据使用一些字符来代替。
> sed '1,5p' data.txt #打印1到5行
> sed '1,5=' data.txt #打印1到5行的行号
> sed '1,5{=;p]}' data.txt #先打印行号,再在下一行打印行中数据
> sed '1,5l' data.txt #打印行中数据,不可打印字符也会使用字符表示
处理文件
处理文件会使用两种命令,分别是命令r,和命令w。命令r将指定的文件数据插入到数据流中,而命令w则将数据流写入指定文件中。sed不会处理插入的数据。
使用格式如下:
> sed '[address]r file1' file2
> sed '[address]w file1' file2
> sed '1r data1.txt' data.txt #将data1.txt中的数据插入到第一行的后面。
> sed '1w data1.txt' data.txt #将data.txt的第一行数据写入data1.txt中。
进阶命令
多行数据
多行数据命令包括n,N,P,D。
命令n跳转到下一行接着执行脚本,命令N将下一行数据加入当前行然后接着执行脚本。命令P和D是命令p和d的多行版本,用于处理多行数据中的第一个数据。
命令n
> cat data.txt #两行数据
> dog
> cat
> sed -n '{
> n #跳转到第二行
> p #执行单行打印数据
> }' data.txt #只会打印第二行数据
命令N
> sed -n '{
> N #将下一行数据加入当前模式空间
> p #打印两行数据,即打印“dog”和“cat”
> }' data.txt
使用命令N后,下一行数据加入到当前模式空间,和之前在模式空间的行当作一行来处理。注意,如果下一行没有数据,则命令N会执行失败从而完成sed。
命令P仅会打印第一个行数据。
如:
> sed -n '{
> N #将下一行数据加入当前模式空间
> P #打印第一个行数据,即只打印“dog”
> }' data.txt #打印两行数据
命令D
如果当前模式空间没有换行符,则命令D的作用与d一致。如果有换行符,则命令D会删除第一个换行符之前的字符包括换行符。并且,**不会读取新的行,而是从当前模式空间开始执行脚本。**这意味这命令N和命令D连用会形成一个循环,D之前的脚本会不停的执行直到文本数据末尾,而命令D后面的脚本不会再执行。
下面给出一个使用同时使用命令D和命令N的例子,该例子会将jack[ \n]ma替换为people[ \n]richer,如果jack ma只存在于一行中,只需简单的使用替换命令s就行,但jack ma可能分成两行存储。为了解决该问题,可以使用命令N和命令D,命令N将下一行加入当前行,之后可以替换跨行的jack ma,而使用命令D可以不断的迭代该过程。
> cat jack.txt
> jack ma,jack
> ma,jack
> ma
> jack ma
>
> sed -n '{
>N
>s/jack\([\n ]\)ma/people\1richer/g # ()和\1是模式替换,参考下文
>P #打印数据,只打印模式空间中第一行的数据
>D #执行D指令,若有换行,则删除一行,并迭代之前的命令
>}' jack.txt
保持空间(缓冲区)
sed使用了两类空间,第一种是模式空间,为当前脚本所工作的空间;另外一个是保持空间,它是一个缓存区。可以使用命令复制数据到缓存区,也可复制缓存区的数据回到模式空间。
命令 | 说明 |
---|---|
h | 从模式空间复制到保持空间 |
H | 从模式空间附加到保持空间 |
g | 从保持空间复制到模式空间 |
G | 从保持空间附加到模式空间 |
x | 交换模式空间和保持空间的内容 |
注意以上操作要么是复制,要么是附加,不会删除数据。也就是说,如果将模式空间的数据复制到保持空间,当前脚本处理的仍旧是模式空间原有的数据。要想处理下一行的数据,要么使用n,要么使用N,要么等待当前脚本处理完当前的行。
控制流
b,t
通过给定b一个地址可以让脚本跳转到特定的标签,如果没有指定标签,则跳转到脚本末尾,接下来会使用脚本处理下一行数据。
下面的命令会替换一行中的所有逗号,这也可以通过使用带替换标记g的替换命令来完成。
> echo "a,b,c,d,e" | sed -n '{
> :start #标签
> s/,/ /1p #替换第一个逗号,并打印行
> /,/b start #有条件跳转。若行中存在逗号,则跳转到start处
>}'
使用命令b时需要给定终止条件或继续条件,否则会无限循环。
t会在命令替换中使用,若成功替换,则跳转到特定标签,否则继续执行接下来的指令。可以使用t完成上面的操作。
> echo "a,b,c,d,e" | sed -n '{
> :start
> s/,/ /1p
> t start #成功执行替换命令后,会跳转到start
>}'
模式替代
在替换指令s中,可以使用一些特殊字符替代匹配出的数据。特殊字符有 &,\数字。
==&==是完整的匹配数据的别名,假设有指令:
> sed '{s/ta[a,b]x/"&"/}' #给匹配出的数据加上双引号
符号 & 代表了前面匹配出的数据,即taax或者tabx。由于匹配出的数据可能有多种,因此不能使用一个具体的字符串指代,sed使用了符号==&==指代匹配出的数据。
\数字用于指代匹配数据中的一部分,使用 () 标识要指代的数据,之后,使用 \1指代第一个, \2指代第二个,其他以此类推。
例如:
> echo "a+b a-b" | sed -n '{s/a\([+-]\)/a"\1"b/g;p}' #原括号需要转义,\1指代前面的+和-,该指令给给+和-加上双引号
awk
awk有多个版本,这里介绍gawk版本的使用方法。gawk是一种格式化输入输出文本文件的工具,它读入具有格式的文本,然后加以处理后输出。
它提供了如下功能:
- 可以定义变量保存数据。可以在awk内定义变量,之后可以使用这些变量。
- 结构化编程。提供了if、while、for、do-while等结构编程所需要的方法。
- 可以提取出数据元素中的各个数据,处理后然后输出。通过记录分隔符分割数据得到记录,然后使用字段分隔符分割字段得到各个字段,这些字段的值赋予到各个内建变量上。
- 可以使用数学计算和字符串操作来修改数据,这可以通过使用内建数学函数、内建字符串函数或者自定义函数完成。
gawk使用格式
使用格式
$ gawk 'BEGIN{} {} /pattern/{} $1 ~ /pattern/{} $1 !~ /pattern/{} END{}'
正则
在gawk中,可以使用正则匹配记录,若匹配成功,则会执行后面的代码段。
$ gawk '/richer/{print "it has money"}' #如果记录中有richer,则打印信息
BEGIN与END
BEGIN和END是两个关键字,用于声明在脚本开始执行和执行完毕后,要执行的代码段。
$ gawk 'BEGIN{print "file begin"} END{print "file end"}'
波浪符==~==
波浪符用于在一个字段中使用正则匹配数据,可以使用感叹号==!==对正则取反。
$ gawk '$1 ~ /1/{print $0}' #如果第一个字段存在1,则打印记录
$ gawk '$2 !~ /2/{pritn $0}' #如果第二个字段不存在2,则打印记录
gawk常用的选项
选项 | 说明 |
---|
变量
变量有两种类型:自定义变量和内建变量。自定义变量没有类型,直接定义即可,在gawk中,还可以定义数组,数组索引为字符串。内建变量也有两类:一类用于设置处理输入输出的相关参数,另外一类则包含了环境的一些信息。
自定义变量
脚本中定义变量
直接定义,没有类型
$ gawk '{val = 1;print val}'
注意,获取变量的值不使用美元符。
命令行中定义变量
可以直接定义变量,也可以使用选项==-v==后定义变量。
$ gawk -v val=2 'BEGIN{print val}' #-v指在BEGIN之前定义变量
$ gawk val=2 'BEGIN{}' #在BEGIN内无法使用命令行定义的变量
数组
索引可以为字符串。
gawk 'BEGIN{val["a"] = 1;val["b"] = 2}'
内建变量
gawk会将输入的数据切割成记录,然后再将记录切割成字段。切割方式默认是以换行切换数据得得记录,以空格切割记录得到字段。也可通过在BEGIN或者命令行中设置一些选项来改变这一默认行为。另外,gawk不仅可以用字符分割,也可直接指定每个段的长度。
字段与记录相关选项
选项 | 说明 |
---|---|
FIELDWIDTHS | 用逗号分割的一串数字,每个数字为各段长度,不使用字符切割 |
FS | 输入字段分隔符 |
RS | 输入记录分隔符 |
OFS | 输出字段分隔符 |
ORS | 输出记录分隔符 |
数据变量
包含一些环境信息。
变量名 | 说明 |
---|
结构化编程
if
if( condition ){
statments #没有分号;
}else{
statments
}
for
两种形式,c形式和类似shell的形式。
#c形式
for(i=0; i<10; ++i)
{
statment
}
#类shell
for(var in array){ #有括号
statments
}
while
while ( condition ){
statment
}
do-while
do{
statment
}while(condition)
函数
打印函数
格式化打印
类似c语言,也有控制宽度、小数点位数和控制左对齐的功能
gawk '{
print %-3.5f #宽度为3,小数点后5位,左对齐
}'
自定义函数
定义格式
function func([varibales])
{
statements
}
在定义函数的时候,函数必须出现在所有代码块(包括BEGIN)的前面。
函数也可以定义在一个文件中,gawk可以使用-f参数使用该文件中的函数。
内建函数
数学函数
字符串函数
时间函数