Linux sed 详解

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

##sed简介   sed命令说简单也简单,说复杂也复杂,看你怎么用。如果只是简单的使用的话知道s,a,i,d命令就可以了。如果要深入一点的了解的话就要理清楚sed的处理流程,知道什么是pattern space,知道什么是hold space,它们的作用是什么。   对于sed命令刚刚开始感觉很乱,傻傻分不清楚位置匹配命令。这里有一个小的技巧,发现对于sed命令有一个比较明显的特点,就是大多数的模式都是先匹配位置在执行命令。这个需要在使用过程中多注意,慢慢的就会发现基本上都可以替换为这中模式。

###pattern space(模式空间) 与 hold space(持有空间)   pattern space可以看做是sed读取行存放和处理的内存空间,sed是按行来处理数据的,sed每从输入流中读取一行就存放在pattern space中,然后进行处理,处理后的结果也存放中pattern space中,然后在读取下一行进行处理,在读取下一行之前会先清楚pattern space,有时候我们需要pattern space处理结果后面用怎么办呢,因为pattern space每一次读取新行之前都会清空,所以不能缓存结果,为了解决这个问题,sed就另外申请了一个空间,这个空间就是hold space,我们可以把pattern space中的处理结果存放在hold space中。

###sed处理流程

###sed命令与匹配概览 Linux sed 详解_第1张图片

Linux sed 详解_第2张图片

##sed基本命令   sed命令主要用来处理文件,如果把文件当做数据库的话,sed命令完成的操作基本上也就是增删改查,查询比较少,查询主要是为了修改。如果只是查询的话可以考虑grep。

###删除

#删除
sed '2d'        fileName            #删除fileName文件的第二行。
sed '2,$d'      fileName            #删除fileName文件的第二行到末尾所有行。
sed '$d'        fileName            #删除fileName文件的最后一行。
sed '/^love/d'  fileName            #删除fileName文件所有以love开始的行。

对于删除需要注意的是删除的匹配到的整行,而不是删除的匹配,例如sed '/love/d' fileName 就是删除fileName中包含love的所有行,而不是只是删除love。

###替换

#替换
sed '1,10y/abc/ABC/' fileName       #将1到10行中的abc替换为ABC
sed '1,10s/abc/ABC/' fileName       #将1到10行中的abc替换为ABC

#对于s命令更加常见的是没有位置的
#将fileName中每一行的第一个pattern(可以使用正则)替换为expect
sed  's/pattern/expect/' fileName 

#如果要全部替换可以使用g(sed中有2个g一个是表示全局,一个表示从
#hold space 去数据到pattern space,这里和多数其它正则表达式一样表示全局)
sed  's/pattern/expect/g' fileName 

#对于替换除了y,s还有一个c命令,一般用法是c\
sed '1 c\sed c change' fileName  #把fileName中的第一行有sed c change替换

#对于替换命令y 和 s的区别在于y是以单个字符为单位进行替换,s是以整体进行替换
echo "abc------a-b-c" | sed 'y/abc/xyz/'   #结果:xyz------x-y-z
echo "abc------a-b-c" | sed 's/abc/xyz/'   #结果:xyz------a-b-c

###添加

#给sedswap.sh文件的第一行加上#!/bin/sh
sed '1 i\#!/bin/sh' sedswap.sh

#在匹配到xxx行的前面一行插入Hello world
sed  '/xxx/i\Hello World' fileName

#在匹配到xxx行的后面面一行插入Hello world
sed  '/xxx/a\Hello World' fileName

##sed命令拾遗

& 引用pattern匹配到的字符串


sed -e 's/pattern/& expect/' fileName
echo "aaaHellobbb" | sed 's/Hello/ & World /'  #结果:aaa Hello World bbb

选择第几个匹配

sed -e 's/a/b/3' fileName      #把第3个a替换为b
echo "aaaabbbb" | sed 's/a/x/3'   #结果:aaxabbbb

!取反

#删除不包含127.0.0.1的行
sed -e '/127.0.0.1/!d' fileName

n 获取匹配下一行

# n 读取下一行,这种在上一行是标签,下一行是变量的时候比较常用
#因为没有办法匹配变量,所以匹配标签,然后提取匹配到的下一行,例如
#username:
#xxxx
#因为姓名xxx不是固定的,不好匹配,直接匹配username:然后找下一行接容易多了
sed  '/username:/n' -e 'p' fileName

###使用其它分隔符

#使用其它分隔符
#表示把所有Hello替换成Hello World。
sed 's#Hello#Hello World#g' fileName 
#不论什么字符,紧跟着s命令的都被认为是新的分隔符。
#所以,“#”在这里是分隔符,代替了默认的“/”分隔符。

###使用()分组

#使用()分组
#思考:怎样把aaatestbbb中的test提取出来呢?注意不是替换或者删除,
#是获取,并且保存到hold space 以便于使用,这里就可以是用()
#像其它正则表达式一样,sed也可以使用()进行分组
#这里我们利用分组来保存匹配,然后使用替换来把分组中的内容放到pattern space中
#然后使用h把pattern space中的内容拷贝到hold space中
echo "aaatestbbb" | sed 's/aaa\(test\)bbb/\1/'

#一个()就表示一个分组,\1表示的第一分组,依次类推第二个分组\2,第三个分组\3 ···
#更加一般的表示
echo "aaatestbbb" | sed 's/.*\(test\).*/\1/'

#放到hold space中
echo "aaatestbbb" | sed 's/.*\(test\).*/\1/;h;g'

###使用x交换pattern space 与 hold space   与pattern space 与 hold space存取相关的主要有4个命令,分别是g,G,h,H。可以把g看做是get的嘛,就是用hold space中覆盖pattern space。G是吧hold space中的内容追加到pattern space中。同理,h可以看做是hold,表示用pattern space中的内容覆盖hold space中。H表示把pattern space中的内容追加到hold space中。

#让World Hello位置互换
echo "World Hello" | sed '/World/h;s/\(World\).*/\1/;x;s/.*\(Hello\)/\1/;G;s/\n/ /'
#当然上面那个比较复杂了,下面来一个简单的
echo "World Hello" | sed 's/\(World\)\(Hello\)/\2 \1/'

###使用r 和 w命令 r是读文件的意思,在sed中就表示从文件中读取内容插入到匹配行之后。还是来一个具体的例子来说一下吧。比如有一个adv文件内容如下:

http://www.freemethod.cn

mylove文件内容如下:

an empty street

An empty house

A hole inside my heart

I'm all alone\n The rooms are getting smaller

I wonder how

I wonder why

执行下面的命令:

 sed '/empty/r adv' mylove

结果如下:

an empty street

http://www.freemethod.cn

An empty house

http://www.freemethod.cn

A hole inside my heart

I'm all alone

The rooms are getting smaller

I wonder how

I wonder why

我们可以发现实在匹配到empty的行的后一行加了adv文件中的内容,我们并没有使用a命令。

w命令就是写命令,在sed就是把匹配到的行写入指定的文件中,我们还是使用上面的mylove文件,执行下面的命令:

sed '/empty/w result' mylove

执行完result文件中的内容为:

an empty street

An empty house

我们可以看到把匹配到的2行写入到了result文件中。

##sed的几个命令选项

-i选项,表示直接在文件中修改


sed '1 i\#!/bin/sh' sedswap.sh

sed -i '1 i\#!/bin/sh' sedswap.sh
#对应上面2个命令看一下sedswap.sh文件就可以发现执行完第一个命令只是
#输出到标准输出,sedswap.sh文件并没有修改,而第2个命令,
#没有在标准输出中输出了,而是在sedswap.sh文件就添加了。

-e选项 -e选项后面直接跟一个完整的命令


#如果一个命令的话-e可以省略,例如下面2个命令就是一样一样的
sed  '/xxx/a\Hello World' fileName
sed  -e '/xxx/a\Hello World' fileName

#多个命令的话就要在每一命令前面都加上-e参数或者使用;分割
sed  -e '/xxx/i\Hello World' -e '/xxx/a\Hello World' fileName
#sed   '/xxx/i\Hello World; /xxx/a\Hello World' fileName

-n选项 安静模式不输出

这里有一个误区,很多资料说-n是只输出匹配行,其实是不太准确的,-n就是不输出,包括匹配到的都不输出。可以通过一个例子来验证一下,假设num文件中的内容为:

111111111

222222222

333333333

444444444

555555555

sed 's/333/xxx/' num   #结果如下:

111111111

222222222

xxx333333

444444444

555555555

sed -n 's/333/xxx/' num #是没有输出的
sed -n 's/333/xxx/p' num #结果如下:

xxx333333

sed 's/333/xxx/p' num #结果如下:

111111111

222222222

xxx333333

xxx333333

444444444

555555555

从上面的结果来看,我们可以总结处理-n是不输出,p(小p)是输出匹配(sed处理的行),所以一般我们-n参数和p命令结合起来使用,就只是输出处理之后的结果。

-f选项 从文件中读取命令

这个选项一直没有测试正确,很多资料也只是简单说是执行sed脚本。其实这个命令是从指定的文件中读取命令,不是脚本,只是sed命令,例如我们要执行命令

sed 's/333/xxx/p' num

先在只需要把s/333/xxx/p写入到一个文件中,这里假设是command文件,接下来只需要执行下面的命令就可以了:

sed -f command num

注意:文件中每一行是一个命令,命令不要加引号。 下面来一个更加具体的例子来说明一下,假设有一个文件word中的内容如下:

we have joy fun

we have joy in the sun

hello my trusted friend

command中的内容如下:

s/have/had/

a\append in the end

s/joy/joying/

执行下面的命令:

sed -f command word

结果如下:

we had joying fun

append in the end

we had joying in the sun

append in the end

hello my trusted friend

append in the end

##sed小结   注意sed是以行为单位作为处理和结果输出的,你可以把sed看做是一个简单的编程语言,它按行来处理脚本。它可以使用一个主内存pattern space和一个寄存器hold space。当你发现sed可以完成一些不可思议的事情的时候,你就会理解那些大神的思维是如此令人惊叹。

转载于:https://my.oschina.net/u/2474629/blog/775221

你可能感兴趣的:(操作系统,python,数据库)