Linux正则表达式以及Sed使用学习

正则表达式是熟悉和使用Linux系统的最重要的基础,其中grep,find,awk以及sed等对其依赖更大。本节将总结一下Linux中常用的正则表达式使用方法。

正则表达式中特殊字符

  • . : 表示任何单个字符
  • [] : 包含一个字符序列,表示匹配序列中其中一个字符
  • - : 出现在[]中,表示一个序列范围.如[a-z]表示26个小写的英文字母
  • ^ : 出现在[]中,表示对序列去反。如[^a-z]表示匹配不是a-z的其他字符
  • * : 匹配某一个字符的0个或1个或多个实例
  • ? : 匹配某一个字符的0个或1个实例
  • + : 匹配某一个字符的1个或多个实例
  • $ : 匹配行尾。如test$指匹配以test结尾的行
  • ^ : 匹配行首。如^test指匹配以test开始的行
  • \< : 匹配词首
  • > : 匹配词尾
  • \ : 转移特殊字符,如果需要匹配上述特殊字符,用反斜杠转义

sed使用说明

sed命令:

1
sed [OPTION]... {script-only-if-no-other-script} [input-file]...

sed使用

data文件内容

1
2
3
4
this is a dog a
this is a cat
this is a money
this is a fish

用s命令进行替换

替换时若出现单引号,直接将脚本用双引号括起来即可。
1.将一行中第一个匹配的特定字符串替换

1
sed "s/a/an/" data

注意不会改变原文件,只是会打印到标准输出流。若要保存可以重定向到新的文件中。

2.讲一行中所有匹配的特定字符串匹配,使用g参数

1
sed "s/a/an/g" data

3.使用-i参数直接修改文件内容

1
sed -i "s/a/an/g" data

4.在每一行的开头添加内容

1
sed "s/^/#/" data

5.在每一行的结尾添加内容

1
sed "s/$/#/" data

6.指定特定行替换,或指定特定范围内的行替换

1
2
sed "3s/an/a/" data
sed "1,2s/an/a/" data

7.只替换每一行的第一个a:

1
sed "s/a/an/1" data

8.只替换每一行的第二个a:

1
sed "s/a/an/2" data

9.只替换每一行第二个以后的所有a

1
sed "s/a/an/2g" data

多个匹配

多个匹配可以用分好将匹配规则连接。

1
sed "s/an/a/g;s/dog/cat/g" data

上述命令等价于:

1
sed -e "s/an/a/g" -e "s/dog/cat/g" data

显示被匹配的变量

&可以表示被匹配的变量,即若被匹配的变量为”abc”,则&代表abc。

1
2
#功能为在每个an外加[]
sed -e "s/an/[&]/g" data

圆括号匹配

被圆括号括起来的匹配可以当做变量使用,注意圆括号匹配时括号需要”\”转义。变量按顺序使用\1,\2指代。

1
sed "s/this \(.*\) an \(.*\)/\1:\2/" data

结果:

1
2
3
4
is:dog an
is:cant
is:money
is:fish

sed命令

data内容:

1
2
3
4
this is a dog a
this is a cat
this is a money
this is a fish

N命令

N命令的作用是把下一行的命令纳入当做缓冲区。也就是缓冲区包括两行.

1
2
#只匹配缓冲区的第一个this
sed "N;s/this/that/" data

执行命令结果为:

1
2
3
4
that is a dog a
this is a cat
that is a money
this is a fish

1
sed "N;s/\n/,/" data

执行命令结果为:

1
2
this is a dog a,this is a cat
this is a money,this is a fish

a命令和i命令

  1. i命令的作用是在指定行前面插入一行,行号写在i前面,中间空格可有可无;如果不写行号默认在所有行的前面插入

    1
    2
    #在第一行前面插入 this is my test i
    sed "1i this is my test i" data
  2. a命令的作用是在指定行后追加内容,行号写在a前面,若不写表示所有行后。也可用$代表最后一行,不过一定要有空格.

1
2
#在第一行后插入 this is my test a
sed "1a this is my test a" data
  1. 可以使用匹配来添加
1
2
#若匹配到cat,则在当前行后追加一行 this is test match a
sed "/cat/a this is test match a" data

c命令

c命令是替换匹配的行

1
2
#替换第二行
sed "2 c this is test c" data

结果:

1
2
3
4
this is a dog a
this is test c
this is a money
this is a fish

1
2
#用匹配替换
sed "/fish/c this is the test c" data

结果:

1
2
3
4
this is a dog a
this is a cat
this is a money
this is the test c

d命令

d命令删除指定的行,可指定范围

1
2
#删除第2到3行
sed "2,3 d" data

结果:

1
2
this is a dog a
this is a fish

1
2
#删除找到cat指定的行
sed "/cat/d" data

结果:

1
2
3
this is a dog a
this is a money
this is a fish

1
2
#删除第二行到结尾
sed "2,$ d" data

结果:

1
this is a dog a

p命令

p命令的作用是打印匹配到的行.注意打印的时候使用-n参数。sed默认输出处理后的文本,使用-n参数阻止默认输出。

1
2
#打印匹配到cat的行
sed -n "/cat/p" data
1
2
#打印符合从一个模式当另一个模式的行
sed -n "/dog/,/money/p" data

结果:

1
2
3
this is a dog a
this is a cat
this is a money

1
2
#打印从第一行到匹配到的哪一行
sed -n "1,/cat/p" data

结果:

1
2
this is a dog a
this is a cat

=命令

=参数用于打印匹配到的行号

1
2
#打印含有cat的行号
sed -n "/cat/=" data

综合运用

将下列中所有的100替换为当前行号

1
2
3
4
5
6
7
8
9
10
11
12
13
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100
hmset '99_p_100' 'm_19' 100 't_19' 100 'semm_19' 100

shell命令如下:

1
sed = data | sed "N;s/\([0-9]*\)\n\(hmset '99_p_\)[0-9]*\(' 'm_19' \)[0-9]*\( 't_19' \)[0-9]*\( 'semm_19' \)[0-9]*/\2\1\3\1\4\1\5\1/"

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
hmset '99_p_1' 'm_19' 1 't_19' 1 'semm_19' 1
hmset '99_p_2' 'm_19' 2 't_19' 2 'semm_19' 2
hmset '99_p_3' 'm_19' 3 't_19' 3 'semm_19' 3
hmset '99_p_4' 'm_19' 4 't_19' 4 'semm_19' 4
hmset '99_p_5' 'm_19' 5 't_19' 5 'semm_19' 5
hmset '99_p_6' 'm_19' 6 't_19' 6 'semm_19' 6
hmset '99_p_7' 'm_19' 7 't_19' 7 'semm_19' 7
hmset '99_p_8' 'm_19' 8 't_19' 8 'semm_19' 8
hmset '99_p_9' 'm_19' 9 't_19' 9 'semm_19' 9
hmset '99_p_10' 'm_19' 10 't_19' 10 'semm_19' 10
hmset '99_p_11' 'm_19' 11 't_19' 11 'semm_19' 11
hmset '99_p_12' 'm_19' 12 't_19' 12 'semm_19' 12
hmset '99_p_13' 'm_19' 13 't_19' 13 'semm_19' 13

Comment and share

Linux Regex正则表达式库

标准的C/C++库不支持正则表达式。在Posix函数库中包含了正则表达式库。

## 正则表达式匹配框架

标准的正则表达式匹配框架:

  • 编译正则表达式.
  • 匹配正则表达式.
  • 释放正则表达式.

编译正则表达式

1
2
#include <regex.h>
int Regcomp(regex_t* preg, const char* regex, int cflags);

参数说明

  • preg : 用来保存编译之后的结果
  • regex : 正则表达式字符串,表示被编译的正则表达式。
  • cflags : 编译控制参数
    • REG_EXTENDED : 使用扩展正则表达式模式
    • REG_ICASE : 对规则中字符串不区分大小写
    • REG_NOSUB : 只检查是否有符合规则的子串。

返回值

编译成功返回0,否则返回非0

匹配正则表达式

1
2
3
4
5
6
7
8
9
10
typedef struct {
regoff_t rm_so;
regoff_t rm_eo;
} regmatch_t;
int regexec(const regex_t* preg,
const char* string,
size_t nmatch,
regmatch_t pmatch[],
int eflags);

参数说明

  • preg : 上述编译之后的正则表达式regex_t指针。
  • string : 被匹配的字符串。
  • match : 被匹配的个数。告诉函数regexec最多可以把多少个匹配结果写入pmatch,一般为pmatch数组的长度。
  • pmatch : 匹配结果数组。
    • rm_so : 满足子串在string中的起始偏移量
    • rm_eo : 满足子串在string中的结束偏移量
  • eflags : 匹配的特性
    • REG_NOTBOL : 是否为第一行
    • REG_NOTEOL : 是否是最后一行

返回值

0表示匹配成功,1表示REG_NOMATCH。

报错信息

1
size_t regerror(int errcode, const regex_t* preg, char* buf, size_t buffer_size);

参数说明

  • errcode : 来自regcomp和regexec的错误码。
  • preg : 编译后的正则表达式
  • buf : 缓冲区错误信息字符串
  • buffer_size : 缓冲区最大长度。

释放正则表达式

1
2
//释放reget_t指针,无返回值。
void regfree(reget_t* preg);

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <regex.h>
#include <stdlib.h>
int main() {
regex_t preg;
int iErr = 0;
regmatch_t subs[256];
char acReg[] = "[0-9a-zA-Z]+$";
iErr = regcomp(&preg, acReg, REG_EXTENDED);
if (iErr) {
printf("compile reg error\n");
exit(1);
}
iErr = regexec(&preg, "12345", 256, subs, 0);
if (REG_NOMATCH == iErr) {
printf("no match\n");
} else {
printf("match\n");
}
}

参考资料:

Comment and share

  • page 1 of 1

魏传柳(2824759538@qq.com)

author.bio


Tencent


ShenZhen,China