1. 正则
正则表达式基本元素包括:普通字符、元字符(如*、^、[]等)
shell命令如grep、sed、awk使用正则表达式
1.1 基本的正则表达式
元字符:
(1)*
0个或多个在*字符之前的一个普通字符
例子:
hel*o 表示匹配前面的‘l‘字符0次或多次
(2).
匹配任意一个字符
(3)^
匹配行首,或其后字符的非
例子:
^ab 表示以ab开头的
^[0-9] 表示以任意一个数字开头的
[^0-9] 表示不再范围内的所有字符
(4)$
匹配行尾
例子:
^$ 表示空行
^.$ 表示只含一个任意字符的行
^a[a-z]*c$ 表示以a开头,以c结尾,中间是任意个小写字母字符的字符串
(5)[ ]
匹配字符集合
例子:数字集合、字母集合
[0123456789]、[0-9] 表示0~9中任意一个数字字符
[a-z] 表示小写a到z之间任意一个字符
(6) \
转义符,屏蔽一个元字符的特殊意义
(7) \<\>
精确匹配符号
例子:
\<abc\> 只匹配abc这个单词,不匹配包含abc字符的其它串,如不匹配 mabcn
(8) \{n\}
匹配前面一个字符出现n次
(9)\{n,\}
匹配前面字符至少出现n次
(10)\{n,m\}
匹配前面字符出现n~m次
1.2 扩展的元字符
(1)?
匹配0个或1个在其之前的一个普通字符
例子:
a?b 匹配ab、aab
(2)+
匹配1个或多个在其之前的一个普通字符
(3) ()和 |
表示一个字符集合或用在expr中,结合使用表示一组可选的字符
| 可表示多个正则表达式的或关系
例子:
re(a|e|o)d 匹配read、reed、reod
等同 re[aeo]d
1.3 通配
shell使用正则表达式中的一些元字符实现通配功能
(1)*
任意个的任意字符
例子:
*.cpp 表示以任意字符开头,结尾是 .cpp的文件
(2)?
表示一个任意字符
例子:
a?.cpp 表示以a开头,后面跟一个任意字符,结尾是 .cpp 的文件
(3)^
表示取反
(4)[]
表示范围内的一个字符
例子:
[a-z]*.cpp 表示以a到z开头,后面是任意字符,结尾是 .cpp的文件
(5){}
表示一组表达式的集合 或的关系
例子:
{*.cpp , *.py} 表示所有的cpp文件或py文件
1.4 grep命令
全面搜索正则表达式,并打印(文本搜索工具)
grep [选项] [模式] [文件...]
选项:
-c :只输出匹配字符串的数量
-i:搜索时忽略大小写
-h:查询多文件时不显示文件名
-l:只列出符合匹配的文件名,不列出具体的匹配行
-n;列出所有的匹配行,并显示行号
-s:不显示不存在或无匹配文本的错误信息
-v:显示不包含匹配文本的所有行
-w:匹配整个单词
-x:匹配正行
-r:递归搜索(搜索当前目录和子目录)
-q:禁止输出任何结果,以退出状态表示搜索是否成功(0:搜索成功; 1:未搜索到满足模式的文本行; 2:命令或程序出错)
打印状态: echo $?
-b:打印匹配行 距文件头部的偏移量,单位 字节
-o:与-b结合使用,打印匹配的词距文件头部的偏移量,单位字节
-E:支持扩展的正则表达式
-F:不支持正则表达式,按字符串的字面意思进行匹配
模式:用双引号或单引号括起来,表示要搜索的字符串或用正则表达式
搜索正则的元字符如搜索 *、. 要转义
- 也要转义
例子:
(1)在当前目录下的所有.c和.h文件里面搜索以‘#‘开头的行,并显示行号
grep -n ‘^#‘ *.c *.h
(2)在当前目录的*.c文件里搜索以5个 - 符号开头的文本行 (- 符号也要转义)
grep -n ‘^\-\{5\}‘ *.c
POSIX增加的字符类:
[:upper:] 表示[A-Z]
[:lower:] 表示[a-z]
[:digit:] 表示[0-9]
[:alnum:] 表示[0-9a-zA-Z]
[:space:] 表示空格或Tab
[:alpha:] 表示[a-zA-Z]
[:cntrl:] 表示ctrl键
[:graph:]或[:print:] 表示ASCII码33~126之间的字符
[:xdigit:] 表示16进制数字[0-9A-Fa-f]
2. sed命令
2.1 sed命令使用
(1)sed是一个非交互式文本编辑器,可对文本文件、标准输入进行编辑(标准输入可以是来自键盘输入、文件重定向、字符串、变量、管道的文本)。
从其中读取数据复制到缓冲区,然后读取命令行或脚本的第一个命令,对此命令要求的行号进行编辑并重复执行,直到命令行或脚本中所有命令执行完毕
使用场景:①编辑相对交互式文本编辑器而言很大的文件
②编辑命令太复杂,在交互式文本编辑器中难以输入
③对文件扫描一遍,但是需要执行多个编辑函数
效果:sed是对缓存区中复制来的文件副本进行操作,不影响原文件,要保存修改的内容,需要将输出重定向到另一个文件
sed ‘sed命令‘ file1 > file2 将file1中文件执行sed命令,并保存到file2
(2)
①在shell中输入命令调用sed
sed [选项] ‘sed命令‘ 操作文件
②在脚本中写sed命令,通过sed命令调用
sed [选项] -f sed脚本文件 操作文件
③脚本中写sed命令,直接执行该脚本文件
./sed 脚本文件 操作文件
操作文件如果没有指定,则默认是标准输入
选项:
-n:不打印所有的行到标准输出
-e:将下一个字符串解析为sed编辑命令,如果只传递一个编辑命令给sed则-e可省略(每一个编辑命令前都要加-e)
-f:正在调用sed脚本文件
(3)定位文本、编辑命令
定位文本:指定行号或通过正则匹配
x:第x行
x,y:从x到y行
/pattern/:查询包含模式的行
/pattern/pattern/:查询包含两个模式的行
/pattern/,x:从与模式匹配的行到x行之间的行
x,/pattern/:从x行到匹配行之间的行
x,y!:查询不包括x和y行的行
编辑命令:即具体做什么操作(前面没有-)
p:打印匹配行
=:打印文件行号
a\:在定位行号之后追加文本信息
i\:在定位行号之前插入文本信息
d:删除定位行
c\:用新文本替换定位文本行,是替换整个行
s:使用替换模式替换相应模式,替换字符串,而不是整个行
r:从另一个文件中读文本
w:将文本写入到另一个文件,后面要跟新文件名
y:变换字符
q:第一个模式匹配完成后退出
l:显示与八进制ASCII码等价的控制字符
{}:在定位行执行的命令组
n:读取下一个输入行,用下一个命令处理新的行
h:将模式缓冲区的文本复制到保持缓冲区
H:将模式缓冲区的文本追加到保持缓冲区
x:互换模式缓冲区和保持缓冲区的内容
g:将保持缓冲区的内容复制到模式缓冲区
G:将保持缓冲区的内容追加到模式缓冲区
2.2 sed命令使用例子
(1)打印某文件的第一行到标准输出
只打印第一行,则编辑命令为 ‘1p‘ ,不打印其他行,要加上sed命令的选项 -n
sed -n ‘1p‘ a.sb
如果不加-n选项呢,则先打印第一行,再打印整个文件内容
(2)多个编辑命令
匹配以a开头,中间是其他小写字母或空格,以c结尾的行,先打印行号,再打印行的内容(第5行、6行)
sed -n -e ‘/^a[a-z ]*c$/=‘ -e ‘/^a[a-z ]*c$/p‘ a.sb
(3)用脚本形式
在行6后面追加一些内容
#!/bin/sed -f 6a\ a new line \ #在行6下一行添加此行内容 \ 换行 another new line #又添加一行
执行脚本:添加可执行权限,再对该文件执行此脚本
chmod u+x append.sed ./append.sed a.sb
(4)匹配元字符
如果要查找 * . $ - 等字符,要转义 \*
如:查找打印含 - 字符的行
sed -n ‘/\-/p‘ a.sb
(5)通过元字符/正则匹配
$ 字符在正则中表示行结尾,在sed命令中表示 最后一行
如:打印最后一行
sed -n ‘$p‘ a.sb #打印最后一行 sed -n ‘$‘p a.sb #打印最后一行
打印行5到结尾行:
sed -n ‘5,$p‘ a.sb
(6)整行替换与字符串替换
c\新文本 和 s/匹配串/新串/[替换选项]
原内容:
对ab进行两种替换:
sed ‘/ab/c\hahahaha‘ a.sb #含 ab的行被替换为hahahaha
sed ‘s/ab/hahahaha/‘ a.sb #将ab字符串替换为hahahaha
串s替换的选项:s/被替换串/新串/[替换选项] 前面没有-
g:替换文本行中所有出现被替换字符串的地方,而不是该行首先出现匹配的地方
p:与-n选项结合,只打印替换行
w 文件名:将输出定向到一个文件
替换时特殊字符:& 表示被替换字符串
例,要给串123前后假设*号 s/123/*&*/g
(7)变换字符
sed ‘y/被变换的字符序列/变换后的字符序列/‘ 输入文件
将被变换字符序列中字符逐个用变换字符序列中字符替代
例:将某文件中a变成A,b变成B,c变成C
sed ‘y/abc/ABC/‘ a.sb
(8)其他用法
①处理匹配行的下一行
②sed缓冲区处理
3. awk编程
3.1 awk编程模型
awk程序由一个主输入循环维持(此循环由awk框架实现),主输入循环自动一次读取输入文件行以供处理,我们再添加处理文件行的动作(即不需要我们写main、不需要打开文件、读取文件、关闭文件,只需要写处理文件行的内容就行了)
特殊字段:
BEGIN:在主输入循环之前执行
END:在主输入循环之后执行
3.2 awk调用
①shell
awk [-F 域分隔符] ‘awk程序段‘ 输入文件
②awk调用脚本文件
awk -f awk脚本文件 输入文件
③直接执行可执行文件
./awk脚本文件 输入文件
3.3
awk语句由模式和动作组成。模式是一组用于测试输入行是否需要执行动作的规则,动作是包含语句、函数、表达式的执行过程
awk支持?、+两个扩展元字符
awk视输入文件是格式化的文件
(1)awk记录和域
awk将每个输入文件的行定义为记录,行中每个字符串定义为域(域之间用空格、tab、其他符号间隔)
用 $ 指定执行动作的域,每条记录域从 $1 开始(而$0表示所有的域,即整行)
①域操作符 $ 后可以跟数字、也可是是变量、变量表达式
awk ‘BEGIN{a=1;b=2} {print $(a+b)}‘ a.sb //即print $3
②改变域间隔符
空格是默认间隔,tab视作连续空格
awk -F"," ‘print $2‘ a.sb #一种是通过-F选项修改
awk ‘BEGIN {FS=","} {print $1,$2}‘ a.sb #通过环境变量FS指定域分隔符
FS可通过正则表达式设置域分隔符
(2)关系和布尔运算符
布尔:
逻辑或: ||
逻辑与:&&
逻辑非:!
(3)条件和循环语句
条件里面可以写正则,语句和C类似
if if/else if/else else
while(条件表达式) {动作}
do {动作} while(条件)
for(设置计数器初值;测试计数器;计数器变化) {动作}
(4)表达式
表达式由数值、字符常量、变量、操作符、函数、正则表达式组合而成
变量:字符串值、数值类型
算术运算符:
(5)系统变量
一种用于改变awk的默认值,如FS修改域分隔符;一种用于定义系统值,处理文本时可读取,如域数量、记录数、文件名,是动态的。
(6)格式化输出
printf (格式控制符,参数)
格式控制符:修饰符、格式符
(7)内置字符串函数
如替换gsub,不带第三个参数时,作用于整个行(行中所有域);第三个参数指定作用的域
(8)向awk脚本传递参数
./awk NUM=3 FS="," a.sb # = 号两边不能有空格
(9)数组
格式类似C,但awk数组不需要定义数组类型和大小,可直接赋值后使用
数组是关联数组
数组的索引可以是数字,但该数值与数组存储地址无关
访问数组:for (variable in array) {对array[variable]的动作}
in的用法:判断array[index]是否在数组中(返回1或0) index in array
两个数组形式的系统变量:
ARGV:命令行参数 个数是ARGC,参数从ARGV[0]到ARGV[ARGC-1]
ENVIRON:环境变量
两个打印命令行参数和系统变量的示例脚本:
脚本1:
#!/usr/bin/awk -f BEGIN { for (x=0;x<ARGC;x++) print "arg" x ":" ARGV[x] }
执行: 并传入数个参数
脚本2:
#!/usr/bin/awk -f BEGIN { for (i in ENVIRON) print i "=" ENVIRON[i] }
执行效果:
3.4 例子
(1)判断空行
awk ‘/^$/{print "a blank line"}‘ a.sb
输入文件有一个空行,就打印一行字符串
(2)查看 /etc/passwd文件中注册名为root的用户信息
awk ‘BEGIN {FS=":"} $1~/root/‘ /etc/passwd
$1后面, ~ 匹配正则
(3)if条件判断
如果域2大于等于56,就打印正行
awk ‘{if($2>=56) print $0}‘ a.sb
(4)判断某文件有多少空行
在遍历行时,如果匹配到空行,变量加1,在所有行结束后(END),打印此变量的值
awk ‘/^$/{n++} END{print n}‘ a.sb
注意: /^$/{n++;} 条件和执行语句之间不能是换行,见(7)
(4)计算此文件第三列数字的平均值
注意本文件有一个空行,因此是第三列数字相加除以3;也要注意如果为空文件或全是空行的情况,打印 empty
awk ‘!/^$/{total += $3;n++} END{if(n>0) print total/n;else {prin"empty"}}‘ a.sb
awk ‘!/^$/{total += $3;n++} END{if(n>0) print total/n;else {prin"empty"}}‘ b.sb
(5)计算第三列数字的平均值
如果有一些行数据不合法,比如不是空行但没有第三个域,或者第三个域不是数字,则要加上条件:
写法1:在表达式里面加if条件
awk ‘!/^$/{if(!(NF<3) && ($3~/[0-9]+$/)){total += $3;n++}} END{if(n>0) print total/n;else {print "empty"}}‘ a.sb
注意,if后面要执行的语句要用{}括起来
写法2:在遍历行时就判断,在内部表达式内只要toal和n的操作,这样更清晰
awk ‘(!/^$/)&&(NF>=3 && $3~/[0-9]+$/){total += $3;n++} END{if(n>0) print total/n;else {print "empty"}}‘ a.sb
(6)向awk脚本传递参数
test.awk脚本文件内容:打印域的数量不是传入参数个数的行
#!/usr/bin/awk -f NF !=NUM {print $0}
执行:
./test.awk NUM=3 FS=" " a.sb
(7)一个注意的地方【计算空行数量】
文件改为有两个空行,如下图:
脚本1:
#!/usr/bin/awk -f /^$/ { n++; } END { print n; }
执行效果:
脚本2:
#!/usr/bin/awk -f /^$/{ n++; } END { print n; }
执行效果:
awk是每调入文件的一行,就对其执行一遍脚本文件,而脚本文件估计是以换行符和{} 区分语句块。对于脚本1, /^$/ 表示打印空行,而后面的 n++ 则对每一行都调用一次,因此结果为7;
--------
grep:用于搜索
sed:用于修改、编辑文本文件中某些行,也可用于搜索
awk:访问文本文件,操作某些数据,用于搜索和统计计算
---------
4. 文件操作的一些命令
4.1 sort
类似awk,sort将文本看作多条记录,每条记录有多个域
sort [选项] [输入文件]
4.2 uniq
4.3 join
4.4 cut
4.5 paste
4.6 split
4.7 tr
4.8 tar
5. 关于变量和引用
6. 结构
7. I/O重定向