1. 正则
正则就是各种各样的字符组合在一起形成的一串有规律的字符串,编程语言、shell 脚本都需要用到正则表达式,可以利用正则来完成一些复杂的需求。
学习正则需要用到四个工具grep、egrep、sed、awk,其中 egrep 是 grep 的扩展,这俩者通常被归类为同一个工具。学好正则对编写shell脚本有很大的帮助。
2. grep命令
- grep含义:是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
grep家族总共有三个:grep,egrep,fgrep。
grep [参数] “关键词” [文件]
参数 | 参数含义 |
---|---|
-c | 行数。 |
-i | 不区分大小写。 |
-v | 取反。 |
-n | 显示行号。 |
-r | 遍历所有子目录。 |
-w | 精准匹配查找的内容并输出所在行。 |
-q | 一般用于用于 if 逻辑判断,意思为:执行结果找到了,会返回0,否则,返回1。 |
-A | 后面跟数字,过滤出符合要求的行以及下面 n 行。 |
-B | 后面跟数字,过滤出符合要求的行以及上面 n 行。 |
-C | 后面跟数字,同时过滤出符合要求的行以及上下各 n 行。 |
- -help | 在线帮助。 |
grep主要参数示例:
- grep 最简单的用法就是后面加一个字符串,然后匹配含有这个字符串的行
[root@sc ~]# mkdir grep
[root@sc ~]# cd grep/
[root@sc grep]# cp /etc/passwd .
[root@sc grep]# pwd
/root/grep
[root@sc grep]# ls
passwd
[root@sc grep]# grep 'nologin' passwd #过滤nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
php-fpm:x:1004:1004::/home/php-fpm:/sbin/nologin
zabbix:x:997:995:Zabbix Monitoring System:/var/lib/zabbix:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
memcached:x:996:994:Memcached daemon:/run/memcached:/sbin/nologin
- grep -c 选项查看行数
[root@sc01 grep]# grep -c 'nologin' passwd
22
- grep -n 选项显示行号
[root@sc01 grep]# grep -n 'nologin' passwd
2:bin:x:1:1:bin:/bin:/sbin/nologin
3:daemon:x:2:2:daemon:/sbin:/sbin/nologin
4:adm:x:3:4:adm:/var/adm:/sbin/nologin
5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
9:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10:operator:x:11:0:operator:/root:/sbin/nologin
11:games:x:12:100:games:/usr/games:/sbin/nologin
12:ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13:nobody:x:99:99:Nobody:/:/sbin/nologin
14:systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
15:dbus:x:81:81:System message bus:/:/sbin/nologin
16:polkitd:x:999:998:User for polkitd:/:/sbin/nologin
17:sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
18:postfix:x:89:89::/var/spool/postfix:/sbin/nologin
19:chrony:x:998:996::/var/lib/chrony:/sbin/nologin
20:ntp:x:38:38::/etc/ntp:/sbin/nologin
21:tcpdump:x:72:72::/:/sbin/nologin
22:nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
27:php-fpm:x:1004:1004::/home/php-fpm:/sbin/nologin
28:zabbix:x:997:995:Zabbix Monitoring System:/var/lib/zabbix:/sbin/nologin
29:apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
30:memcached:x:996:994:Memcached daemon:/run/memcached:/sbin/nologin
- grep -i 选项不区分大小写查看
[root@sc grep]# grep -i 'nologin' passwd
[root@sc grep]# vi passwd #修改passwd文件里nologin把字母变大写
- grep -v 选项是取反
[root@sc01 grep]# grep -v 'nologin' passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mysql:x:1000:1000::/home/mysql:/bin/bash
user1:x:1001:1001::/home/user1:/bin/bash
user2:x:1002:1002::/home/user2:/bin/bash
user3:x:1003:1003::/home/user3:/bin/bash
- grep -r 选项把一些子目录下面的文件进行遍历
把 /etc/ 下含有 root 字符串的文件都列出来
[root@sc01 grep]# grep -r 'root' /etc/
- grep -A 后面跟数字,过滤出符合要求的行以及下面 n 行
[root@sc01 grep]# grep -nA2 'root' passwd
1:root:x:0:0:root:/root:/bin/bash
2-bin:x:1:1:bin:/bin:/sbin/nologin
3-daemon:x:2:2:daemon:/sbin:/sbin/nologin
--
10:operator:x:11:0:operator:/root:/sbin/nologin
11-games:x:12:100:games:/usr/games:/sbin/nologin
12-ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
- grep -B 后面跟数字,过滤出符合要求的行以及上面 n 行
[root@sc01 grep]# grep -nB2 'root' passwd
1:root:x:0:0:root:/root:/bin/bash
--
8-halt:x:7:0:halt:/sbin:/sbin/halt
9-mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10:operator:x:11:0:operator:/root:/sbin/nologin
- grep -C 后面跟数字,同时过滤出符合要求的行以及上下各 n 行
[root@sc01 grep]# grep -nC2 'root' passwd
1:root:x:0:0:root:/root:/bin/bash
2-bin:x:1:1:bin:/bin:/sbin/nologin
3-daemon:x:2:2:daemon:/sbin:/sbin/nologin
--
8-halt:x:7:0:halt:/sbin:/sbin/halt
9-mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10:operator:x:11:0:operator:/root:/sbin/nologin
11-games:x:12:100:games:/usr/games:/sbin/nologin
12-ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
grep结合正则表达式主要符号示例:
正则表达式 | 正则表达式符号的含义 |
---|---|
^ | 匹配正则表达式的开始行。 |
$ | 匹配正则表达式的结束行。 |
^$ | 空白行。 |
’ ^# ’ | 表示列出以 # 号开头的行。 |
’ [^ 0-9] ’ | ^ 放到 [ ] 里面来表是 “非” 的意思,会把除 0-9 这个范围的数字以外的内容带颜色显示出来。 |
’ ^ [^ 0-9] ’ | 第一个 ^ 表示以什么开头,第二个 ^ 放到 [ ] 里面来表是 “非” 的意思, 以非 0-9 这个数字范围的的字符开头。 |
. | 代表所有的单个字符。 |
’ r . o ’ | 也是有一个取值范围的,r 和 o 中间如果有字符也会被列出来。 |
* | 匹配左边字符 0-n 次,n 代表任意数字。 |
’ o * o ’ | * 号左边的字符重复 0-n 次,n 表示一个随意的数字,* 号右边接着匹配。 |
.* | 贪婪匹配,任意长度的任意字符,会匹配所有的。 |
? | 匹配任意一个字符。 |
’ o ? t ’ | ? 号左侧的字符表示重复次数是 0 或 1 ,左侧没有匹配,右侧接着匹配。 |
+ | 匹配其前面一个字符出现至少一次(在扩展正则表达式中) |
’ o + o ’ | +号左边的字符重复 1 次或者多次,+ 号右边接着匹配。 |
[…] | 单个字符,如[A]即A符合要求 。 |
[ - ] | 范围,如[A-Z],即A、B、C一直到Z都符合要求 。 |
{…} | 可以用数字指定前面那个字符的重复范围 |
‘o\ {2\ }’ | 匹配 2 个 o 。 |
‘o\ {0,3 \ }’ | 匹配 0-3 个 o 这个范围。 |
(…) | 组合 |
丨 | 或者 |
\ | 忽略正则表达式中特殊字符的原有含义。 |
<或\b | 锚定词首,其后面的任意字符必须作为单词首部出现。 |
>或\b | 锚定词尾,其前面的任意字符必须作为单词尾部出现。 |
- ’ [0-9] ’ 表示 0-9 的范围,只要在这个范围内的都会被列出来
要注意的是所谓 0-9 不是说 0到9 的基数的意思,是指包含 0-9 的字符串就会被列出来。
- 加 -v 选项就是显示不包含 0-9 的行,也可以理解为把不包含数字的行列出来
[root@sc grep]# grep -v '[0-9]' passwd
[root@sc grep]#
- ’ ^# ’ 表示列出以 # 号开头的行,所以 ^ 就是表示某个字符开头的行
[root@sc grep]# cp /etc/inittab .
[root@sc grep]# ls
inittab passwd
[root@sc grep]# vim inittab
- 加 -v 选项就可以过滤掉#号开头的行
- ’ [^0-9] ’ 表示非 0-9,^ 只要放在方括号内就表示 “非” 得意思,会把内容列出来然后 0-9 之外的字符都会显示颜色
- ’ ^ [^ 0-9 ] ’ “以” “非” 0-9 这个数字范围的的字符开头,第一个 ^ 是以什么开头,第二个 ^ 是非的意思
- . 表示匹配任意单个字符
- ’ * ’ 表示 * 号匹配前面的字符0次或多次
- ’ .* ’ 任意长度的任意字符,会匹配所有的,类似于通配
- { } 可以用数字指定前面那个字符的重复范围,但是要加上脱义符或者 egrep
- 如果不想写脱义符可以加个 -E 选项或者使用 egrep
- ’ + ’ 表示匹配 + 号前面的字符1次或多次
- ?号前面的字符重复次数为 0 或 1
- | 是 “或者” 的意思
- ( ) 是 “组合” 的意思
3. sed命令
sed能够做到grep能做到的功能,sed工具的强项在于替换一些字符。
sed介绍:流编辑器过滤和转换。
sed [选项] {脚本(如果没有其他脚本)} [输入文件]
】
常用参数 | 常用参数含义 |
---|---|
s | 替换掉匹配的内容 |
g | 在行内进行全局替换 |
p | 打印行 |
d | 删除行 |
I | 不区分大小写 |
& | 在sed命令中代表上次匹配的结果 |
= | 打印匹配行的行号 |
-n | 取消默认的完整输出,只要需要的 |
-e | 允许多项编辑 |
-i | 修改文件内容 |
-r | 不需要转义 |
–help | 显示这个帮助并退出 |
–version | 输出版本信息并退出 |
sed主要参数示例:
- 使用 sed 匹配字符串,将需要匹配的字符串写在 / / 里,-n 的作用是只打印匹配的行,其他行不打印,p 的作用是打印的意思
- . 和 * 符号 sed 都支持
- 在 sed 命令中使用 + { } | ,需要加 -r 选项来脱义
- sed 可以用数字来指定打印某一行或者某个范围,而且不需要加 / /
- -e 选项可进行多个操作,例如匹配第一行的同时可以匹配某个字符串的所在行
- 如果出现重合的情况会打印两行,因为它们不是同一个表达式
- 加上大写的 I 可以在匹配时不区分大小写
- 使用 -d 选项是把剩下的行列出来,前面的行不显示
- 使用 -i 选项可以删除指定的行
- 还可以针对字符串去删除
- 使用 s 可以替换字符,g 是全局打印,和 vim 的替换方式非常像
- 还可以使用正则表达式
- 把第一段和最后一段的字符串进行替换
- 如果需要替换的字符串里含有 /,就得用 \ 来脱义,或者使用 @ 和 # 来表示 /
- 把英文字母全部替换成空字符串
- 把所有行的前面加上一个字符串
4. awk命令
awk 比 sed、grep 要复杂一些,awk支持分段,例如像passwd文件的内容很有规律用冒号分成七段,awk 可以针对每一段进行匹配。
awk介绍:awk 是一个强大的文本分析工具,相对于 grep 的查找,sed 的编辑,awk 在其对数据分析并生成报告时,显得尤为强大。简单来说 awk 就是把文件逐行的读入,默认以空格为分隔符将每行切片,切开的部分再进行各种分析处理。 awk 是行处理器,相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息。
- awk最简单的用法就是照某个字符进行分割,然后可以选择打印某一段
- 打印所有的段
- 不分段,直接打印文件内容
- 如果忽略了 awk -F 这个参数,没有指定分隔符,默认将会以空格或者空白字符为分隔符去打印
[root@sc awk]# vim 1.txt
- 打印多段内容
- 指定打印的时候以什么字符进行分割,例如我以 # 号进行分割
- 匹配 oo 指定字符所在的行
- 指定匹配某一段并且此段包含指定字符的行,例如我指定匹配第一段包含有 oo 字符串的行
这就是 awk 强大的地方,并且同样匹配正则表达式
- 在 awk 中使用正则表达式不用加脱义符,默认就可以支持
- awk 支持同时写多个表达式同时查找含有 /root/ 1,3行, /user/ 1,3,4行
- 使用 | 也可以
- awk 还可以使用关系运算符
这个命令表示匹配第三段含有 0 的行
- 以上使用关系运算符进行的匹配是按照实际数字大小来匹配的,如果要按 ASCII 码的大小匹配的话,它认为这是字符串,不是数字,加上双引号即可
- 第 7 段不等于 /sbin/nologin 需要加 ! 号
- 在 awk 命令里使用比较运算符
- OFS 用于指定 print 用到时候的打印的分隔符
- 想要写得规整一些就加上 if 条件判断语句
- 加上 NR 表示所有内容的行号
- 加上 NF 表示所有内容的段
- NF 或者 NR 可以作为一个判断条件,例如我只打印前10行
- 给 NR 和 NF 加上 $ 符
- 使用 awk 命令对文件的某一段进行赋值
- 使用 awk 命令进行 tot (求和的意思)
5. 扩展
把一个目录下,过滤所有*.php文档中含有eval的行:grep -r --include="*.php" ‘eval’ /data/
打印某行到某行之间的内容:http://ask.apelearn.com/question/559
sed转换大小写:http://ask.apelearn.com/question/7758
sed在某一行最后添加一个数字:http://ask.apelearn.com/question/288
删除某行到最后一行:http://ask.apelearn.com/question/213
打印1到100行含某个字符串的行:http://ask.apelearn.com/question/1048
awk 中使用外部shell变量:http://ask.apelearn.com/question/199
awk 合并一个文件:http://ask.apelearn.com/question/493
把一个文件多行连接成一行:http://ask.apelearn.com/question/266
awk中gsub函数的使用:http://ask.apelearn.com/question/200
awk 截取指定多个域为一行:http://ask.apelearn.com/question/224
过滤两个或多个关键词:http://ask.apelearn.com/question/198
用awk生成以下结构文件:http://ask.apelearn.com/question/5494
awk用print打印单引号:http://ask.apelearn.com/question/1738
合并两个文件:http://ask.apelearn.com/question/945
awk的BEGIN和END:http://blog.51cto.com/151wqooo/1309851
awk的参考教程:http://www.cnblogs.com/emanlee/p/3327576.html
awk语法结构:
awk -F ':' 'BEGIN{语句} {if(条件){语句1;语句2;语句3} } END{语句}' filename
打印某行到某行之间的内容:
sed -n '/tss/,/sas/p' /etc/passwd
sed转换大小写:
1. 把每个单词的第一个小写字母变大写:
sed 's/\b[a-z]/\u&/g' filename
2. 把所有小写变大写:
sed 's/[a-z]/\u&/g' filename
3. 大写变小写:
sed 's/[A-Z]/\l&/g' filename
sed在某一行最后添加一个数字:
sed -r 's/(^a.*)/\1 12/' test
sed -r 's/^a.*/& 12/' test
打印1到100行含某个字符串的行:
sed -n '1,100{/abc/p}' 1.txt
awk 中使用外部shell变量:
a=2; echo "a:b:c:d"|awk -F ":" -v get_a=$a '{print $get_a}'
awk 合并一个文件:
awk 'NR==FNR {a[$1]=$2} NR>FNR {print $0,a[$1]}' 1.txt 2.txt
说明:
awk '{print NR,FNR}' 1.txt 2.txt //首先理解NR和FNR的不同(awk支持同时操作多个文件内容)
当NR==FNR其实就是第一个文件的内容
当NR>FNR,其实就是第二个文件的内容
把一个文件多行连接成一行:
方法一:
a=`cat file`;echo $a
方法二:
awk '{printf("%s ",$0)}' file
方法三:
cat file |xargs
awk中gsub函数的使用 :
awk 'gsub(/www/,"abc")' /etc/passwd // passwd文件中把所有www替换为abc
awk -F ':' 'gsub(/www/,"abc",$1) {print $0}' /etc/passwd // 替换$1中的www为abc
awk 截取指定多个域为一行 :
用awk指定分隔符把文本分为若干段。如何把相同段的内容弄到一行?
以/etc/passwd为例,该文件以":"作为分隔符,分为了7段。
for i in `seq 1 7`
do
awk -F ':' -v a=$i '{printf $a " "}' /etc/passwd
echo
done
过滤两个或多个关键词:
grep -E '123|abc' filename // 找出文件(filename)中包含123或者包含abc的行
egrep '123|abc' filename //用egrep同样可以实现
awk '/123|abc/' filename // awk 的实现方式
awk用print打印单引号:
awk 'BEGIN{print "a'"'"'s"}'
awk 'BEGIN{print "a'\''s"}'
awk 'BEGIN{print "a\"s"}'