主要内容:
grep、egrep的使用,基本/扩展正则、sed的使用(非交互、逐行处理、常用命令与选项)
补充:grep [-E]选项,表示允许使用扩展的正则表达式(同等于egrep)
一、grep 与 egrep 的使用
grep 和 egrep 是 Unix 和 Linux 系统中用于文本搜索的强大工具。它们可以根据指定的模式(正则表达式)在文件中查找匹配的行。虽然 egrep 是 grep 的一个变种,但在现代系统中,grep 已经集成了 egrep 的功能,因此通常推荐使用 grep 并指定选项来实现相同的效果。
1、grep 基本用法
- 格式:grep [选项] 模式 [文件...]
- 常用选项:
-i:忽略大小写。
-v:反向匹配,显示不匹配的行。
-r:递归搜索目录下的所有文件。
-n:显示匹配行的行号。
-E:使用扩展正则表达式(等同于 egrep)。
-o:只显示匹配的部分,而不是整行。
示例:
基本搜索:
grep "pattern" file.txt
忽略大小写:
grep -i "pattern" file.txt
反向匹配:
grep -v "pattern" file.txt
递归搜索:
grep -r "pattern" /path/to/directory
显示行号:
grep -n "pattern" file.txt
使用扩展正则表达式:
grep -E "pattern" file.txt
2、egrep 基本用法
egrep 是 grep -E 的别名,用于支持扩展正则表达式。在现代系统中,grep 已经集成了 egrep 的功能,因此通常推荐使用 grep -E。
文本处理顺序:以行为单位,逐行进行处理,默认只输出与表达式相匹配的文本行
- 格式1:egrep [选项] ‘正则表达式’ 文件...
- 格式2:前置命令 | egrep [选项] ‘正则表达式’
- 常用选项:
[-i] 忽略字母大小写
[-v] 条件取反
[-c] 统计匹配的行数 //与wc -l 效果相同
[-q] 静默、无任何输出,一般用于检测(通过$?返回值,0为有匹配。非0为无匹配)
[-n] 显示出匹配结果所在的行号
[--color] 标号显示匹配字串
示例:
基本搜索:
egrep "pattern" file.txt
忽略大小写:
egrep -i "pattern" file.txt
反向匹配:
egrep -v "pattern" file.txt
递归搜索:
egrep -r "pattern" /path/to/directory
显示行号:
egrep -n "pattern" file.txt
案例:典型的应用场合
扩展正则表达式支持更多的元字符和功能,例如 +、?、| 等。
-
匹配一个或多个字符:
grep -E "a+" file.txt
-
匹配零个或一个字符:
grep -E "a?" file.txt
-
匹配多个模式之一:
grep -E "pattern1|pattern2" file.txt
grep 命令不带-E选项时,支持基本正则匹配模式。比如“word”关键词检索、“^word”匹配以word开头的行、“word$”匹配以word结尾的行等。
例如:输出以“r”开头的用户记录
[root@svr5 ~]# grep '^r' /etc/passwd
root:x:0:0:root:/root:/bin/bash
rpc:x:32:32:Portmapper RPC user:/:/sbin/nologin
例如:输出以“localhost”结尾的行
[root@svr5 ~]# grep 'localhost$' /etc/hosts
127.0.0.1 localhost.localdomain localhost
若使用grep -E或egrep命令,可支持扩展正则匹配模式,能够自动识别 |、{} 等扩展正则表达式中的特殊字符;
[root@svr5 ~]# grep -E '^(root|daemon)' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
同等于
[root@svr5 ~]# egrep '^(root|daemon)' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
二、正则表达式概述
正则表达式(Regular Expression,简称 regex 或 regexp)是一种用于匹配字符串中字符模式的强大工具。它广泛应用于文本搜索、替换、验证和提取等操作。正则表达式由普通字符(如字母、数字)和元字符(具有特殊意义的字符)组成,通过这些字符的组合可以描述复杂的字符串模式。
1.基本正则表达式(Basic Regular Expressions,BRE)
基本正则表达式使用较少的元字符,通常需要反斜杠 \ 进行转义。(可直接使用grep)
正则符号 | 含义 | 示例 | 说明 |
^ | 匹配行首 | ^abc | 以abc开头的行 |
^# | 以#号开头的行(比如注释行) | ||
$ | 匹配行尾 | abc$ | 以abc结尾的行 |
^$ | 空行 | ||
[] | 集合,匹配除换行符外的任意单个字符 | [abc] | 例如 a、b 或 c |
[^] | 匹配不在方括号内的任意一个字符 | [^abc] | |
. | 匹配除换行符外的任意单个字符 | a.c | 匹配 abc、a1c、aAc 等 |
* | 匹配前一个字符任意次数 注意:*不允许单独使用 | a* | 匹配 a、aa、aaa 等。 |
(abc)* | 0个或多个连续的abc | ||
.* | 任意长度的任意字符串,包括空行 | ||
\{n\} | 匹配前面的字符恰好 n 次 | (ab)\{3\} | 匹配ababab |
\{n,m\} | 匹配前面的字符至少 n 次,但不超过 m 次 | (ab)\{1,3\} | 匹配ab、abab、ababab |
\{n,\} | 匹配前面的字符至少 n 次 | (ab)\{2,\} | 匹配2个及以上连续的ab |
\(\) | 保留、组合为整体 | ab{1,3} | 匹配ab、abb、abbb |
\(ab\){1,3} | 匹配ab、abab、ababab |
2.扩展正则表达式(Extended Regular Expressions,ERE)
(需要使用egrep或grep -E)
正则符号 | 含义 | 示例 | 说明 |
+ | 最少匹配一次 | a+ | 一个或多个连续的a |
(abc)+ | 一个或多个连续的abc | ||
? | 最多匹配一次 | a? | 0个或1个a |
(abc)? | 0个或1个abc | ||
{n,m} | 匹配前一个字符n到m次 | (ab){1,3} | 匹配ab、abab、ababab |
() | 组合为整体 | ab{1,3} | 匹配ab、abb、abbb |
(ab){1,3} | 匹配ab、abab、ababab | ||
| | 或者 | root|bin | 匹配root、bin |
\b | 单词边界 | \broot\b | 匹配单词root、不匹配keroot、rooty、brooty等字符串 |
3.匹配指定字符集合内的任何一个字符,[ ]内加【^】可取反
示例 | 说明 |
[abcd_?] | 匹配a、b、c、d、_、? |
[a-z] | 匹配任意小写字母 |
[A-Z] | 匹配任意大写字母 |
[0-9] | 匹配任意数字 |
[a-Z] | 匹配任意字母 |
[a-Z0-9] | 匹配任意字母或数字 |
[^A-Z] | 匹配包括非大写字母的行 |
^[^a-z] | 匹配不以小写字母开头的行 |
4.整体及边界匹配
正则符号 | 含义 | 示例 | 说明 |
() | 组合为整体 | ab{1,3} | 匹配ab、abb、abbb |
(ab){1,3} | 匹配ab、abab、ababab | ||
| | 或者 | root|bin | 匹配root、bin |
\b | 单词边界 | \broot\b | 匹配单词root、不匹配keroot、rooty、brooty等字符串 |
\ | 单词的开头 | \ | 匹配以th开头的单词 |
\> | 单词的结束 | \ | 作用与\broot\b相同 |
\w | 字母数字下划线 | \wa | 匹配xa,不匹配#a |
\s | 匹配空白 | \sa | 匹配 a,不匹配xa |
\d | 匹配数字 | -P\da | 匹配5a,不匹配xa |
练习1:基本正则【^】、【$】、【[]】、【[^]】
[root@svr7 opt]# head -5 /etc/passwd > user //准备练习素材
[root@svr7 ~]# cat user
root:x:0:0:root:/root:/bin/bash
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
例如:过滤以root开头的行
[root@svr7 opt]# grep ‘^root’ user
root:x:0:0:root:/root:/bin/bash
例如:过滤以bash结尾的行
[root@svr7 opt]# grep 'bash$' user
root:x:0:0:root:/root:/bin/bash
例如:过滤空行
[root@svr7 opt]# grep '^$' user
例如:过滤包含‘root’的行
[root@svr7 opt]# grep 'root' user
root:x:0:0:root:/root:/bin/bash
例如:匹配集合中任意单个字符(即r o o t)
[root@svr7 opt]# grep '[root]' user
root:x:0:0:root:/root:/bin/bash
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
结果同上
[root@svr7 opt]# grep '[rot]' user //匹配集合中任意单个字符(即r o t)
例如:匹配含任意小写字母的行
[root@svr7 opt]# grep '[a-z]' user
例如:匹配含任意大写字母的行
[root@svr7 opt]# grep '[A-Z]' user
例如:匹配含任意字母的行
[root@svr7 opt]# grep '[a-Z]' user
例如:匹配含任意数字的行
[root@svr7 opt]# grep '[0-9]' user
例如:匹配除数字的行,[]集合中的【^】代表取反
[root@svr7 opt]# grep '[^0-9]' user
例如:匹配除字母数字的行,可匹配特殊符号
[root@svr7 opt]# grep '[^a-Z0-9]' user
例如:匹配含字母数字的行
[root@svr7 opt]# grep '[a-Z0-9]' user
练习2:基本正则【.】、【*】
例如:匹配r与t之间有2个任意字符的行
[root@svr7 opt]# grep 'r..t' user
root:x:0:0:root:/root:/bin/bash
例如:匹配r与t之间有3个任意字符的行,无则不输出
[root@svr7 opt]# grep 'r...t' user
注意:错误用法,注意:【*】不允许单独使用,非通配符
例如:grep '*' user
例如:匹配*前一个字符o任意次数(0次数)都行
[root@svr7 opt]# grep 'ro*t' user
root:x:0:0:root:/root:/bin/b-ash
例如:匹配任意单个字符,文档中每个字符都为任意字符
[root@svr7 opt]# grep '.' user
root:x:0:0:root:/root:/bin/bash
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
注意:单个字符匹配,除换行符(\n)以外的每个字符,都为任意单个字符
例如:【.*】的组合在正则中,相当于通配符*的效果
[root@svr7 opt]# grep '.*' user
root:x:0:0:root:/root:/bin/bash
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
注意:匹配任意字符,包括空行
例如:输出“r”开头且以“sh“结尾的用户记录,即中间可以是任意字符
[root@svr7 opt]# grep 'r.*sh' user
root:x:0:0:root:/root:/bin/bash
练习3:基本正则【\{n\}】、【\{n,m\}】、【\{n,\}】、【\(\)】
例如:匹配前一个字符o可以有2个的行
[root@svr7 opt]# grep 'ro\{2\}t' user
root:x:0:0:root:/root:/bin/bash
例如:匹配前一个字符o可以有3个的行
[root@svr7 opt]# grep 'ro\{3\}t' user
例如:匹配前一个字符o可以有1~2个的行
[root@svr7 opt]# grep 'ro\{1,2\}t' user
root:x:0:0:root:/root:/bin/bash
例如:匹配前一个字符o可以有2~4个的行
[root@svr7 opt]# grep 'ro\{2,4\}t' user
root:x:0:0:root:/root:/bin/bash
例如:匹配前一个字符o可以有4~6个的行
[root@svr7 opt]# grep 'ro\{4,6\}t' user
例如:匹配前一个字符o可以有1个以上的行
[root@svr7 opt]# grep 'ro\{1,\}t' user
root:x:0:0:root:/root:/bin/bash
例如:匹配前一个字符o可以有3个以上的行
[root@svr7 opt]# grep 'ro\{3,\}t' user
例如:匹配前一个字符连续2个”0:”的行
[root@svr7 opt]# grep '\(0:\)\{2\}' user
root:x:0:0:root:/root:/bin/bash
补充:()小括号的作用是将字符组合为一个整体
练习4:基本/扩展正则【\{n\}】、【\{n,m\}】、【\{n,\}】、【\(\)】
例如:匹配前一个字符o可以有1个以上的行
[root@svr7 opt]# grep 'ro{1,}t' user //grep不支持扩展正则
[root@svr7 opt]# echo $?
1
注意:grep支持基本正则,不支持扩展正则,使用-E选项支持扩展正则且可去掉所有【\】
改成扩展正则的用法:
[root@svr7 opt]# grep -E 'ro{1,}t' user
root:x:0:0:root:/root:/bin/bash
[root@svr7 opt]# egrep 'ro{1,}t' user
root:x:0:0:root:/root:/bin/bash
补充:统计使用bash作登录Shell的用户数量
[root@svr7 opt]# egrep -c '/bin/bash$' /etc/passwd
7
练习5:扩展正则【{n}】、【{n,m}】、【{n,}】、【()】、【+】、【?】、【|】、【\b】
例如:匹配前一个字符o可以有2个以上的行
[root@svr7 opt]# egrep 'ro{2}t' user
root:x:0:0:root:/root:/bin/bash
例如:匹配前一个字符o可以有1到2的行
[root@svr7 opt]# egrep 'ro{1,2}t' user
root:x:0:0:root:/root:/bin/bash
例如:匹配前一个字符o可以有2个以上的行
[root@svr7 opt]# egrep 'ro{2,}t' user
root:x:0:0:root:/root:/bin/bash
例如:匹配前一个字符连续2个”0:”的行
[root@svr7 opt]# egrep '(0:){2,}' user
root:x:0:0:root:/root:/bin/bash
例如:最少匹配字符o一次
[root@svr7 opt]# egrep 'ro+t' user
root:x:0:0:root:/root:/bin/bash
[root@svr7 opt]# egrep 'roo+t' user //结果同上
例如:最多匹配字符o一次
[root@svr7 opt]# egrep 'roo?t' user
root:x:0:0:root:/root:/bin/bash
例如:匹配root、bin的行
[root@svr7 opt]# egrep 'root|bin' user
root:x:0:0:root:/root:/bin/bash
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
例如:匹配以root开头、bin开头的行
[root@svr7 opt]# egrep '^root|^bin' user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@svr7 opt]# cat abc.txt //准备测试文件
the
there
th
_th_
[root@svr7 opt]# egrep ‘the\b’ abc.txt //匹配单词the,后面不能有数字、字母、下划线
the
[root@svr7 opt]# egrep ‘the\>’ abc.txt //结果同上
[root@svr7 opt]# egrep ‘\bth\b’ abc.txt //匹配单词th,前后面都不能有数字、字母、下划线
th
[root@svr7 opt]# egrep ‘\<bth\>’ abc.txt //结果同上
三、sed基本用法
sed(stream editor)是一个强大的文本处理工具,主要用于对文本进行查找、替换、删除、插入等操作。它广泛应用于脚本、自动化任务和文本处理中。以下是 sed 的基本用法和常用命令。
功能:非交互式,基于模式匹配过滤及修改文本,逐行处理并将结果输出到屏幕,可实现对文本的输出、删除、替换、复制、剪切、导入、导出等各种操作;
1、sed命令格式解析
格式:sed [选项] '[定址符]命令' 文件
常见选项:
- -n:静默模式,不自动打印模式空间的内容
- -e:执行多个命令
- -f:从文件中读取命令
- -i:直接修改文件内容
- -r:使用扩展正则表达式(ERE)
补充:条件(定址符),可以是行号或者/正则表达式/:
定址符(执行指令的条件)控制sed需要处理文本的范围;不加则逐行处理所有行
- ① 行号可以使用单个数字表示单行;或者3,5表示连续的多行;省略条件(定址符),则默认逐行处理全部文本;
- ② 匹配正则时,需要使用【/正则表达式/】;
常用动作命令:
相关说明如下:
- ① 条件可以是行号或者/正则表达式/;(没有条件时,默认为所有条件)
- ② 指令可以是增、删、改、查等指令;
- ③ 默认sed会将所有输出的内容都打印出来,可以使用[-n]屏蔽默认输出;
- ④ 选项中可以使用[-r]选项,让sed支持扩展正则,不加[-r]不支持扩展正则;
多个指令可以使用分号【;】隔离(用分号来隔离多个操作)
示例:
1)替换(s)
替换命令是 sed 中最常用的命令之一,用于将匹配到的字符串替换为新的字符串。
格式:sed 's/旧字符串/新字符串/' 文件
sed 's/foo/bar/' example.txt # 将 example.txt 文件中的第一个 foo 替换为 bar。
2)全局替换
默认情况下,sed 只替换每行中第一个匹配到的字符串。要进行全局替换,可使用 g 标志。
格式:sed 's/旧字符串/新字符串/g' 文件
sed 's/foo/bar/g' example.txt # 这个命令将 example.txt 文件中的所有 foo 替换为 bar。
3)删除(d)
删除命令用于删除匹配到的行。
格式:sed '/匹配模式/d' 文件
sed '/foo/d' example.txt # 这个命令删除 example.txt 文件中包含 foo 的所有行。
4)插入(i)和追加(a)
插入和追加命令用于在匹配到的行之前或之后插入新行。
格式:sed '/匹配模式/i 新行' 文件
格式:sed '/匹配模式/a 新行' 文件
sed '/foo/i bar' example.txt # 将包含 foo 的行之前插入 bar
sed '/foo/a bar' example.txt # 将包含 foo 的行之后插入 bar
5)打印(p)
打印命令用于打印匹配到的行。
格式:sed -n '/匹配模式/p' 文件
sed -n '/foo/p' example.txt # 这个命令打印 example.txt 文件中包含 foo 的所有行。
6)多个命令
可以使用 -e 选项或分号(;)来执行多个命令。
格式:sed -e '命令1' -e '命令2' 文件
格式:sed '命令1; 命令2' 文件
sed -e 's/foo/bar/' -e '/baz/d' example.txt
sed 's/foo/bar/; /baz/d' example.txt
# 这两个命令分别将 foo 替换为 bar 并删除包含 baz 的行
练习:准备测试文件
[root@svr7 opt]# cat -n user
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
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
① sed命令的【 -n】 选项
例如:执行p打印等过滤操作时,希望看到的是符合条件的文本。但不使用任何选项时,默认会将原始文本一并输出,从而干扰过滤效果;
[root@svr7 opt]# sed 'p' user //不使用[-n],则不屏蔽默认输出;
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
...
可以发现所有的行都被显示出来了(第1行重复2次),正确的用法应该添加 -n 选项,这样就可以只显示第1行
[root@svr7 opt]# sed -n 'p' user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
...
② sed命令的【 -i】 选项
例如:正常情况下sed命令所做的处理只是把操作结果(包括打印、删除等)输出到当前终端屏幕,而并不会对原始文件做任何更改;
[root@svr7 opt]# sed 'd' user //删除所有行
[root@svr7 opt]# cat user //查看原始文本,并未改动
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
...
若希望直接修改文件内容,应添加选项 -i
[root@svr7 opt]# sed -i '1,4d' user
[root@svr7 opt]# cat user
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
③ 多个指令可以使用分号隔离
例如:用分号来隔离多个操作
[root@svr7 opt]# sed -n '1p;4p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
adm:x:3:4:adm:/var/adm:/sbin/nologin
示例:选项-n屏蔽默认输出,-r扩展正则;指令p打印行、$=行数、=行号、!取反、1~2p奇数行、2~2p偶数行
[root@svr7 opt]# cat -n user //测试文件
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
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
例如:逐行打印所有行(-n屏蔽默认输出;p打印行)
[root@svr7 opt]# sed -n 'p' user
例如:输出第1行
[root@svr7 opt]# sed -n '1p' user
root:x:0:0:root:/root:/bin/bash
例如:输出第2行
[root@svr7 opt]# sed -n '2p' user
bin:x:1:1:bin:/bin:/sbin/nologin
例如:输出第1~3行
[root@svr7 opt]# sed -n '1,3p' user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
例如:输出第2以及后面1行
[root@svr7 opt]# sed -n '2,+1p' user
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
例如:输出第2行,第4行
[root@svr7 opt]# sed -n '2p;4p' user
bin:x:1:1:bin:/bin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
例如:在sed中使用正则表达式输出以root开头的行,匹配的内容要写在两个斜杠中间
[root@svr7 opt]# sed -n '/^root/p' user
root:x:0:0:root:/root:/bin/bash
例如:用sed查找以root或者bin开头的行,【|】为扩展正则,需加【-r】选项使用扩展正则表达式
[root@svr7 opt]# sed -nr '/^root|^bin/p' user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
例如:输出文件的行数
[root@svr7 opt]# sed -n '$=' user
5
例如:显示行号,=号在sed中可以显示行号
[root@svr7 opt]# sed -n '=' user
1
2
3
4
5
例如:输出第2行,并显示行号
[root@svr7 opt]# sed -n '2p;=' user
1
bin:x:1:1:bin:/bin:/sbin/nologin
2
3
4
5
例如:输出除了第2行的内容,加【!】是取反效果
[root@svr7 opt]# sed -n '2!p' user
root:x:0:0:root:/root:/bin/bash
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
例如:打印奇数行
[root@svr7 opt]# sed -n '1~2p' user
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
例如: 打印偶数行
[root@svr7 opt]# sed -n '2~2p' user
bin:x:1:1:bin:/bin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
常见报错:查看后一行+N无法配合【;】使用
[root@svr7 opt]# sed -n '2p;+1p' user
sed:-e 表达式 #1,字符 5:无法将 +N 或 ~N 作为第一个地址
常见报错:查看单独的2行不能使用【,】分隔,需使用【;】
[root@svr7 opt]# sed -n '2p,4p' user
sed:-e 表达式 #1,字符 3:命令后含有多余的字符
常见报错:取反格式错误
[root@svr7 opt]# sed -n '2p!' user
sed:-e 表达式 #1,字符 3:命令后含有多余的字符
示例:指令d实现对应行的删除并输出(只作输出,不更改源文件)
例如:删除第2行
[root@svr7 opt]# sed -n '2d' user //删除操作,不能加-n,否则看不到输出
[root@svr7 opt]# sed '2d' user //删除第2行
root:x:0:0:root:/root:/bin/bash
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
例如:删除第3行、第4行以外的所有行
[root@svr7 opt]# sed '3,+1!d' user
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
例如:删除第3~5行
[root@svr7 opt]# sed '3,5d' user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
例如:删除包含nologin的行
[root@svr7 opt]# sed '/nologin/d' user
root:x:0:0:root:/root:/bin/bash
例如:删除以nologin结尾的行
[root@svr7 opt]# sed '/nologin$/d' user
root:x:0:0:root:/root:/bin/bash
例如:删除文件的最后一行
[root@svr7 opt]# sed '$d' user
root:x:0:0:root:/root:/bin/bash
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
例如:删除空行
[root@svr7 opt]# sed '/^$/d' user
root:x:0:0:root:/root:/bin/bash
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
例如:删除第2行,并显示剩余行的行号
[root@svr7 opt]# sed -n '2d;=' user //删除第2行,并显示剩余行的行号
1
3
4
5
例如:删除第2行之外的行,并显示剩余行的行号
[root@svr7 opt]# sed -n '2!d;=' user
2
示例:指令s实现对应文本的替换(只作输出,不更改源文件)
[root@svr7 opt]# cat test.txt //测试文件
2017 2011 2018
2017 2017 2024
2017 2017 2017
注意:不指定行数,默认把所有行匹配到的第1个2017替换成6666
[root@svr7 opt]# sed 's/2017/6666/' test.txt
6666 2011 2018
6666 2017 2024
6666 2017 2017
例如:把第2行匹配到的第1个2017替换成6666
[root@svr7 opt]# sed '2s/2017/6666/' test.txt
2017 2011 2018
6666 2017 2024
2017 2017 2017
例如:把第2行匹配到的第2个2017替换成6666
[root@svr7 opt]# sed '2s/2017/6666/2' test.txt
2017 2011 2018
2017 6666 2024
2017 2017 2017
例如:把所有行匹配到的第2个2017替换成6666
[root@svr7 opt]# sed 's/2017/6666/2' test.txt
2017 2011 2018
2017 6666 2024
2017 6666 2017
例如:把含有2024的行匹配到的第2个2017替换成6666
[root@svr7 opt]# sed '/2024/s/2017/6666/2' test.txt
2017 2011 2018
2017 6666 2024
2017 2017 2017
例如:把所有行匹配到的2017替换成6666
[root@svr7 opt]# sed 's/2017/6666/g' test.txt
6666 2011 2018
6666 6666 2024
6666 6666 6666
例如:把第1行第1个2017替换成6666,然后第2行第2个2017替换成6666(【;】分离多个操作)
[root@svr7 opt]# sed '1s/2017/6666/;2s/2017/6666/2' test.txt
6666 2011 2018
2017 6666 2024
2017 2017 2017
注意:使用【;】隔离多个操作,当第一条替换完成并执行第二条替换时,因第1个2017已替换,该行剩下2个2017,第二条替换找第3个2017时就无法找到了;所以匹配该行的第3个2017,需要改成2。
[root@svr7 opt]# sed '3s/2017/6666/;3s/2017/6666/3' test.txt
2017 2011 2018
2017 2017 2024
6666 2017 2017
例如:把第3行第1个2017替换成6666,然后第3行的第3个2017替换成6666
[root@svr7 opt]# sed '3s/2017/6666/;3s/2017/6666/2' test.txt
2017 2011 2018
2017 2017 2024
6666 2017 6666
[root@svr7 opt]# sed -e '3s/2017/6666/' -e '3s/2017/6666/2' test.txt
例如:将所有的2017都删除(替换为空串)
[root@svr7 opt]# sed 's/2017//g' test.txt
2011 2018
2024
例如:将2~3行的行首加#号
[root@svr7 opt]# sed '2,3s/^/#/' test.txt
2017 2011 2018
#2017 2017 2024
#2017 2017 2017
例如:将1~3行的行尾加>号
[root@svr7 opt]# sed '1,3s/$/>/' test.txt
2017 2011 2018>
2017 2017 2024>
2017 2017 2017>
例如:将1~3行的行首行尾加#号
[root@svr7 opt]# sed '1,3s/$/#/;s/^/#/' test.txt
#2017 2011 2018#
#2017 2017 2024#
#2017 2017 2017#
例如:将每行的行首2改成3
[root@svr7 opt]# sed 's/^2/3/' test.txt
3017 2011 2018
3017 2017 2024
3017 2017 2017
例如:将每行的行首2改成#2
[root@svr7 opt]# sed 's/^2/#2/' test.txt
#2017 2011 2018
#2017 2017 2024
#2017 2017 2017
同等于
[root@svr7 opt]# sed '/^2/s/2/#2/' test.txt
例如:如何把/bin/bash替换成/sbin/sh(替换符)
报错提示:
[root@svr7 opt]# sed '1s//bin/bash//sbin/sh/' user //直接替换,报错
sed:-e 表达式 #1,字符 8:“s”的未知选项
- 方法1:使用转义符将所有路径转义,但读起来难识别
[root@svr7 opt]# sed 's/\/bin\/bash/\/sbin\/sh/' user
root:x:0:0:root:/root:/sbin/sh
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
- 方法2:只要替换符相同即可替换
[root@svr7 opt]# sed '1s#/bin/bash#/sbin/sh#' user
root:x:0:0:root:/root:/sbin/sh
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
同等于
[root@svr7 opt]# sed 's!/bin/bash!/sbin/sh!' user
[root@svr7 opt]# sed 's@/bin/bash@/sbin/sh@' user
例如:编写脚本,安装httpd服务,要使用82号端口
[root@svr7 opt]# vim httpd_test.sh
#!/bin/bash
yum -y install httpd &> /dev/null
sed -i '/^Listen 80/s/0/2/' /etc/httpd/conf/httpd.conf //将以Listen 80开头的行的0换成2
[root@svr7 opt]#systemctl restart httpd
[root@svr7 opt]#systemctl enable httpd
验证:
[root@svr7 opt]# setenforce 0 //执行脚本前要关闭selinux
[root@svr7 opt]# curl 192.168.4.207:82 //脚本执行完后 查看页面
Hello World
[root@svr7 opt]# netstat -ntulp | grep :82 //查看82号端口
四、Sed的文本块概述
应用场景:文件内插入新行、插入多行文本、替换掉指定的整行文本;
示例:指令i,行前插入文本
例如:不指定行号,则逐行全行之前添加文本
[root@svr7 opt]# sed 'i 666' user
666
root:x:0:0:root:/root:/bin/bash
666
bin:x:1:1:bin:/bin:/sbin/nologin
666
daemon:x:2:2:daemon:/sbin:/sbin/nologin
666
adm:x:3:4:adm:/var/adm:/sbin/nologin
666
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
例如:在第2行之前添加文本
[root@svr7 opt]# sed '2i 666' user
root:x:0:0:root:/root:/bin/bash
666
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
例如:在第1~3行的之前添加文本 666
[root@svr7 opt]# sed '1,3i 666' user
666
root:x:0:0:root:/root:/bin/bash
666
bin:x:1:1:bin:/bin:/sbin/nologin
666
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
例如:在包含root的行之前添加文本 666
[root@svr7 opt]# sed '/root/i 666' user
666
root:x:0:0:root:/root:/bin/bash
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
例如:在包含root和第3~5行之前增加文本 666
[root@svr7 opt]# sed -e '/root/i 666' -e '3,5i 666' user
666
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
666
daemon:x:2:2:daemon:/sbin:/sbin/nologin
666
adm:x:3:4:adm:/var/adm:/sbin/nologin
666
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
示例:指令a,行后插入文本
例如:不指定行号,则逐行全行之后添加文本
[root@svr7 opt]# sed 'a 777' user
root:x:0:0:root:/root:/bin/bash
777
bin:x:1:1:bin:/bin:/sbin/nologin
777
daemon:x:2:2:daemon:/sbin:/sbin/nologin
777
adm:x:3:4:adm:/var/adm:/sbin/nologin
777
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
777
例如:在第2行之后添加文本
[root@svr7 opt]# sed '2a 777' user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
777
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
例如:在第2~4行之后添加文本
[root@svr7 opt]# sed '2,4a 777' user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
777
daemon:x:2:2:daemon:/sbin:/sbin/nologin
777
adm:x:3:4:adm:/var/adm:/sbin/nologin
777
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
例如:在以root开头的行之后添加文本
[root@svr7 opt]# sed '/^root/a 777' user
root:x:0:0:root:/root:/bin/bash
777
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
例如:在包含root的行和第3~4行之后添加文本
[root@svr7 opt]# sed -e '/root/a 777' -e '3,4a 777' user
root:x:0:0:root:/root:/bin/bash
777
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
777
adm:x:3:4:adm:/var/adm:/sbin/nologin
777
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
示例:指令c,替换当前行
[root@svr7 opt]# sed 'c 666' user //替换所有行为666
666
666
666
666
666
例如:替换第1行为666
[root@svr7 opt]# sed '1c 666' user
666
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
例如:替换以bin开头的行为666
[root@svr7 opt]# sed '/^bin/c 666' user
root:x:0:0:root:/root:/bin/bash
666
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
例如:分别对第1行与第3行进行替换成666
[root@svr7 opt]# sed -e '1c 666' -e '3c 666' user
666
bin:x:1:1:bin:/bin:/sbin/nologin
666
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
例如:编写脚本,找到系统中使用bash作为解释器的用户,然后按照“用户名—>密码”的格式存在一个文件中;
- 思路1:查找到以bash解释器结尾的用户,再用sed替换用户后面【:】所有内容,留下的就是用户名
方法1:
[root@svr7 opt]# grep 'bash$' /etc/passwd | sed 's/:.*//'
root
student
lisi
zhangsan
wangwu
abc01
Tom
方法2:
[root@svr7 opt]# sed -n '/bash$/p' /etc/passwd | sed 's/:.*//'
方法3:
[root@svr7 opt]# sed -n '/bash$/s/:.*//p' /etc/passwd //加p显示被替换的行
思路2:查找/etc/shadow中用户名对应的密码行。通过掐头去尾方式过滤出密码
[root@svr7 opt]# grep ‘root:’ /etc/shadow
root:$6$C.j1wjwOSdgoGJnB$UrmNlxKYezuRMnIcrUopqrB46fpWsmvPj0IW82p/CHoETyWnG65lfzhoxikWS0UFIa5pgAK36a5GIpu8R0nbm0::0:99999:7:::
编写脚本
[root@svr7 opt]# vim test05.sh
#!/bin/bash
echo > user //重定向空,重置文件
user=$(sed -n '/bash$/s/:.*//p' /etc/passwd) //定义变量user并将替换后的“用户名”结果放入
for i in $user
do
p=$(grep "$i:" /etc/shadow) //将每个用户的密码信息过滤出来
p1=${p#*:} //从左到右最短匹配到第一个【:】进行“掐头”
p2=${p1%%:*} //从右到左最长匹配到的【:】进行“掐尾”
echo "$i --> $p2" >> user2 //输出“用户—>密码”,并追加重定向user2文件
Done
测试:
[root@svr7 opt]# bash test05.sh
[root@svr7 opt]# cat user2
root --> $6$C.j1wjwOSdgoGJnB$UrmNlxKYezuRMnIcrUopqrB46fpWsmvPj0IW82p/CHoETyWnG65lfzhoxikWS0UFIa5pgAK36a5GIpu8R0nbm0
student --> $6$2s5pSlcENupMYtSO$FVsEEAYXvfiEQ4J3lE18lMCrUfAhLgGZqXYJ.YlVC.93kYJRkPtFjWzKKMKRV3Ef/K6De9VDw9HbU854v7FiZ1
lisi --> !! //!!为未配置密码
zhangsan --> !!
wangwu --> !!
abc01 --> $6$z52aNPzm$Y7ILzEfUM40U6m0mzCXv9WfrNnRypBZqoheMi5UiUCU1PNGDRnflWLSxVJCMjHwbAd/Z2Z24FI/VATleHVtxd0
Tom --> !!
Sed其他示例:
1)修改IP地址
修改虚拟机XML文件的名称值
[root@svr7 opt]# grep ^IPADDR /etc/sysconfig/network-scripts/ifcfg-eth0
IPADDR=192.168.4.7
[root@svr7 opt]# sed -ri '/^IPADDR/s/192.168.1.(.*)/172.16.0.\1' \/etc/sysconfig/network-scripts/ifcfg-eth0
补充:使用【\1】标签可调用本组表达式内第1个用( )保存的匹配结果
2)修改网站根目录
# 将/var/www/html修改为/opt/wwwroot
[root@svr7 opt]# grep "^DocumentRoot" /etc/httpd/conf/httpd.conf
DocumentRoot "/var/www/html"
[root@svr7 opt]# sed -i 's#/var/www/hmlt#/opt/wwwroot#' \/etc/httpd/conf/httpd.conf
小结:
本篇章节为【第二阶段】SHELL-DAY4 的学习笔记,这篇笔记可以初步了解到 grep、egrep的使用,基本/扩展正则、sed的使用(非交互、逐行处理、常用命令与选项)。
Tip:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解