Linux shell三剑客之sed 流式编辑器 详解

目录

sed 流式编辑器

①sed基本原理

②sed程序语法格式

OPTION选项

SCRIPT命令集合

sed寻址

         sed正则表达式

         sed命令

③sed高级

标签命令

滑动窗口

sed中变量的使用和替换问题

④sed实战

 


 

sed基本原理

>>>sed(stream editor)是一个流式编辑器,是一个程序,,用于对输入流执行文本转换操作

>>>sed只能通过一次输入流,每次的输入流只能被处理一次

>>>将读入到模式空间的行号通过sed的行号计数器记录在内存

>>>sed数据缓冲空间
           sed对输入流进行操作,需要将其加载到缓冲空间后才能操作
           sed有两个缓冲空间:模式空间(pattern_space),一直处于活动的空间

                                              保持空间(  hold_space  ),是一个辅助性的空间

>>>对模式空间中行的处理逻辑:

(1)读取输入流的第一行到模式空间中(此时行号计数器记录的行号为1)(移除读取到的行的尾随换行符

(2)当行被预设定的模式匹配上时,则使用sed程序内部的命令进行处理,
         不管内容是否匹配,都会默认自动输出模式空间中处理过后的内容 尾部默认加上换行符

3)清空模式空间中的内容

(4)然后从输入流读取下一行到模式空间(行号计数器更新为下一行),并循环上面的操作,直到输入流中所有行都被处理完成

 

>>>通过一个shell伪代码理解sed程序对输入流的处理逻辑:

for ((line=1;line<=1last_line_num;++line))   #外循环即sed循环

do

    read $line to pattern_space;

    while pattern_space is not null                #内循环即SCRIPT循环

    do

        excute cmd1 in SCRIPT;

        excute cmd2 in SCRIPT;

        excute cmd3 in SCRIPT;

        ……

        auto_print;                         #自动输出

        remove_pattern_space;     #清空模式pattern_space

    done

done

 


 

sed程序语法格式

sed OPSIONS SCRIPT INPUT_STREAM 

说明:

OPSIONS 即选项

SCRIPT 即命令的集合,由寻址和命令组成

INPUT_STREAM 即输入流

 

 

OPTION选项

常用选项

描述

-V

输出sed的版本

-n

禁止 auto_print,输出的内容为空

-e

指定多个表达式          例:sed -e SCRIPT1 -e SCRIPT2 INPUT_STREAM

-f

-f script_file 指定SCRIPT文件(命令集合)

-i

对输入流中的内容进行修改,将修改后的内容写入原文件
-i'_bak' -i有后缀,将原文件备份为file_bak (可以用*表示原文件的文件名)

-r

使用扩展的正则表达式(类似egrep

-s

对于多个文件,每个文件当成独立的输入流,分别处理
(没有
-s,会将多个文件追加当做一个合并的输入流)

 

 

SCRIPT命令集合——由寻址和命令组成

>>>SCRIPT写法规则  addr1{cmd1;cmd2};addr2{cmd3;cmd4}     

          addr表示寻址,cmd表示命令  (命令之间和表达式之间用 ";"隔开)

 

sed寻址 line addressing

>>>为何要寻址

寻址是对模式空间中的内容进行匹配,根据匹配规则决定是否执行对应的命令

若匹配,则执行相应命令

若不匹配,默认情况下直接将模式空间中的内容输出,然后清空模式空间并进入下一个sed循环

>>>寻址即匹配,匹配可能是单行,也可以是一个范围,也可以是用正则表达式去匹配

>>>寻址格式:add1[,add2]:表示从add1add2这个范围

sed常用匹配方式如下:

匹配方式

描述

N

指定一个行号

NM

指定一个范围,从第N行到第M行

FIRST~STEP

从FIRST开始,每隔STEP后的行会被定位(2~3,定位到2、5、8、11行)

$

匹配最后一个文件的最后一行(使用-s或-i时,匹配每个文件的最后一行) $不能用作数学计算

/REGEXP/ \%REGEXP%'

将选择能被正则表达式REGEXP匹配到的所有的行
当正则表达式REGEXP中有符号‘/ ’,必须使用反斜杠对其转义
使用%REGEXP%'不用对 '/ '进行转义
空正则表达式'//',表示引用最后一个正则表达式匹配的结果(s命令's///g'也是)

修饰符“i”,“I”、“M”不能用作空正则表达式

/REGEXP/I  \%REGEXP%I

I表示匹配的时候忽略大小写 不能用i,因为i是个命令表示插入

/REGEXP/M’或‘\%REGEXP%M

多行匹配\n为分隔符
N命令可以实现模式空间有多行
例:echo -e “a\nb\c\d”|sed -n ‘N;s/^[a-z]$/X/Mp’
>>>首先读取第一行到模式空间,行号计数器为1

>>>执行N命令进入多行模式,在当前行后面添加“\n”,并读取第二行内容到模式空间
     行号计数器更新为2,此时模式空间内容为“a\nb”

     用^[a-z]$对模式空间的内容“a\nb”进行匹配(\n为分隔符

     a符合匹配要求被替换为X(无g修饰符,只匹配一次,所以b不被替换)

     输出模式空间中的内容

>>>清空模式空间,读取第三行的内容,行号计数器更新为3,循环上面步骤

ADDR1+N

匹配到ADDR1和其后的N行

ADDR1~N

匹配到ADDR1和其后的行,直到出现N的倍数行 (ADDR1=4,N=3,定位到4、5、6行)

0/REGEXP/

使用0作为起始地址,sed程序会尝试对第一行匹配REGEXP;

若第一行匹配到,则搜索范围立即结束;

若以行号1作为起始地址,则会从第二行开始匹配,直到匹配成功
(第1行至匹配到的行之间所有的行都会输出)

 

寻址之sed正则表达式——用于模式匹配
建议:少用GNU特有的表达式

/正则表达式/

描述

举例

'CHAR'

单个普通字符与自身匹配

‘abc’

'.'

匹配任意单个字符(除换行符)

如果在点号字符的位置没有字符,那么模式不成立(可以是空格)

'*'

紧跟在它前面的单元应匹配零次或多次

a*b 表示b前面可以没有a或者多个a,可以是b或者aaaab

'\+'   GNU extension

紧跟在它前面的单元应匹配一次或多次

a\+b 表示b前面至少有一个a,可以是ab或者aaab

'\?'   GNU extension

紧跟在它前面的单元应匹配零次或一次

/^a\?b$/ 表示输出b或者ab

'.*'

匹配任何字符串,包括空字符串

输出所有行

'.\+'

匹配任何字符串,但包含至少一个字符的字符串

只输出非空白行

'\{N\}'

紧跟在它前面的单元应精准匹配N次

 

'\{N,M\}'

紧跟在它前面的单元应匹配至少N次,最后M次

 

'\{N,\}'

紧跟在它前面的单元应匹配至少N次

 

'\(REGEXP\)'

将正则表达式的一部分括起来组成一个单元,
可以对整个单元使用数量限定符
'\DIGIT'

ifconfig | sed -n 's/\([0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}\)/\1(ip)/gp'  将输出的ip后面追加(ip)

'\DIGIT'

引用\(REGEXP\)

\1表示引用被匹配到的第一个分组

'^'  脱字符

匹配行的开始

sed '/^$/d' test.txt   :过滤空白行

'$'  美元符

匹配到行的结尾

 

'[LIST]'

匹配字符组

[0-9]表示0~9任意数字都可以匹配 ; [ae]表示匹配a或者e
sed -n '/maint[ae]n[ae]nce/p' test.txt,即使maintenance输错也可匹配

'[^LIST]'

排除字符组

[^0-9]表示除了数字0~9都可以匹配

'REGEXP1\|EXGREP2'

GNU extension

连接两个子表达式,表示或的关系,
并使用第一个成功匹配的表达式

 

'REGEXP1EXGREP2'

连接两个正则表达式,表示与的关系

 

'\n'

匹配换行符

 

'\CHAR'

对特殊字符进行转义后匹配

 

'[-]'

字符或数字的范围

[a-zA-Z0-9]

 

 

sed命令


根据作用空间进行划分分为:

>>>作用于模式空间pattern_space的命令(p、d、q/Q、=、y、n、w、r、s、a、i、c、N、D、P)

>>>作用于保持空间hold_space的命令(h、H、g、G、x)

>>>输入一系列命令需要使用使用大花括号{}括起来

sed命令如下

命令

描述

p

强制输出命令,即使使用-n选项,也能输出内容

d

作用是删除,用于删除整个模式空间中的内容,即使d命令后面有命令也不会执行
直接退出SCRIPT循环,进入下一个sed循环
sed ‘/^#/{1!d} test.txt’:删除除了第一行的所有以#开头的行

q/Q

退出当前sed程序,不再执行后面的命令和输入流
q命令被执行后,会输出模式空间内容再退出sed循环
Q命令被执行后,会立即退出,不会输出模式空间内容

=

输出匹配到的行的行号(=命令输出的行号是内存空间,不受-n选项影响)
>>>当“=”和“q”,“Q”命令结合时,会有异常

y

根据映射进行替换,根据位置关系进行替换 (被替换字符串,和替换字符串长度必须相等)'y/abc/def/'

n

作用是输出当前模式空间并清空模式空间,手动读取下一行,行号计数器自动更新到要读取的那一行
sed -n ‘p,n’test.txt :输出奇数行

sed -n ‘n,p’test.txt :输出偶数行

 w filename

将输入流写到指定文件中

r filename

将一个文件插入到数据流中

s

替换匹配的内容
语法格式:s/REGEXP/REPLACEMENT/FLAGS 
>>>REGEXP:使用REGEXP去匹配行,将匹配到的那部分内容替换成REPLACEMENT
>>>REPLACEMENT:用于替换的字符

>>>FLAGS:修饰符
                   g:即gloabl,全局替换,
                         可以将g修饰符替换成NN表示替换第几个匹配到的字符
                   p:强制输出被修改的行,在auto_print之前会多打印一次
                   w filename :将替换的结果写到指定文件中
                   e:若REPLACEMENT的行首是可执行命令,替换成命令执行结果,s命令才会执行成功
                   i/I:忽略REGEXP的大小写
 

需求:将ifconfig && ls || pwd 替换成 ifconfig && pwd || ls

sed ‘s#&&\(.*\) ||\(.*\)#\&\&\2 ||\1#g’
在REPLACEMENT中对&进行了转义,因为&符号在REPLACEMRNT中,表示的是引用REGEXP匹配的所有内容

aic

格式:【a|i|c】 TEXT 当有输出流时,这三个命令就会半路”劫杀“(命令和TEXT之间有无空格,有无转义符都一样)

a命令表示追加到输出流内容中再输出,追加在输出流的尾部
i命令表示插入到输出流内容中再输出,插入在输出流的首部
c命令表示替换掉输出流的内容再输出,替换掉整个输出流  (地址若是一个区间,此命令会用一行替换掉输入流中的多行)
      c命令替换结束会立即退出当前SCRIPT循环SCRIPT循环后面的命令不会被执行)
这三个命令的TEXT是存放在内存中,不会加入模式空间,不受“-n”选项或某些命令影响

NDP

N命令:读取下一行内容追加到当前模式空间的尾部,追加时 原有内容与新内容用换行符\n隔开
             此时行号计数器记录的行号会更新为下一行的行号
             有多行内容时,模式空间格式:line1\nline2\nline3
D命令:删除模式空间中第一个换行符“\n”之前的内容,然后进入到下一轮SCRIPT循环

             实现将模式空间中的内容一行行删除(只有在多行模式才可以生效)
P命令:输出模式空间中第一个换行符“\n”之前的内容,即输出模式空间第一行内容

hH

gGx

h命令:将模式空间中的内容覆盖到保持空间,注意模式空间中的内容仍然保留
H命令:在保持空间尾部加上换行符“\n”,并将模式空间的内容追加到保持空间的尾部,注意模式空间中的内容仍然保留
g命令:将保持空间中的内容覆盖到模式空间
G命令:在模式空间尾部加上换行符“\n”,并将模式空间的内容追加到模式空间的尾部
x命令:交换模式空间和保持空间的内容

 


 

sed高级

 

标签命令

作用:用于控制SCRIPT循环中执行流的循环和分支语句,可以根据标签跳转到某一行命令继续执行

>>>:LABEL

     通过这个格式去定义一个标签,不可放在地址表达式后面

>>>b LABEL

     无条件跳转到标签LABEL上 ,只有bLABEL会导致死循环
     /REGEXP/bx,如果匹配到表达式,就会跳转到LABEL标签处

     如果LABEL省略,则跳转到SCRIPT的尾部,跳到进行auto_print前面

>>>t LABEL
     如果对最近读入s命令能够执行成功,则跳转到LABEL标签处

>>>T LABEL

     如果对最近读入s命令没有执行成功,则跳转到LABEL标签处

 

滑动窗口

>>>输出文件最后五行(单用模式空间,效率慢,适合小文件)
     cat 1.txt | sed -n 'N;N;N;:r;N;$!s/[^\n]*\n//;tr;p'  (若p改为P,即输出文件倒数第5行,P命令用于输出模式空间第一个\n之前的内容)

     /[^\n]*\n/ :表达式匹配到第一行的内容,然后删除它

    第一次执行s命令:1\n2\n3\n4\n5

    第二次执行s命令:2\n3\n4\n5\n6

    第三次执行s命令:3\n4\n5\n6\n7

>>>输出文件最后五行(用模式空间和保持空间,适合大文件)

       cat 1.txt | sed -n 'H;5,${g;s/[^\n]*\n//;h};$p'

     执行流程:

     第一次执行sed循环: 保持空间内容为:\n1                 

     第二次执行sed循环: 保持空间内容为:\n1\n2            

     第三次执行sed循环: 保持空间内容为:\n1\n2\n3      

     第四次执行sed循环: 保持空间内容为:\n1\n2\n3\n4 

     第五次执行sed循环: 保持空间内容为:1\n2\n3\n4\n5

     第六次执行sed循环: 保持空间内容为:2\n3\n4\n5\n6
     …….

 

sed中变量的使用和替换问题

>>>shell中单引号、双引号、无引号时的作用:决定命令行中哪些单词会被shell解析

>>>规范:sed "shell_content"'sed_content' INPUT_STREAM
          1)单引号: 当变量需要被sed解析,而不被shell解析,使用单引号 

                                单引号内所有字符都是普通字符(包括$)

                                单引号内不能包括单引号字符,即使转义也不行,因为此时转义字符也是一个普通字符
                                单引号内包括变量不会被解析,不会命令替换和算术运算,不会进行路径拓展
                                使用sed$!{} 对于这些符号需要用单引号
          2)双引号:对于需要被shell解析的字符,可以使用双引号

                                双引号内的所有字符都为普通字符('\','$','`'除外)
                                对于需要shell解析的字符,可以使用双引号,也可以不加任何引号
          3)无引号:

                               等同于双引号,但会进行大括号和波浪号扩展

 


 

sed实战

1shell变量与sed变量的引号使用

sed -n "`expr $(wc -l <1.txt) - 4`"',$p' 1.txt
>>> `expr $(wc -l <1.txt) - 4`需要被shell解析,不能加单引号
>>> $p的"$"要被sed解析成最后一行,必须使用单引号,避免被shell解析

 

2)将连续空行压缩为一行

sed '/./,/^$/!d' 1.txt

 

3)删除开头空行

sed '/./,$!d' 1.txt

 

4)删除结尾空行
sed ':start;/^\n*$/{$d;N;b start}' 1.txt

>>>/^\n*$/  :匹配到的是空行

 

5)删除每行开头的空格和tab前导空白

sed 's/^[\t ]*//' 1.txt

 

6)过滤所有HTML标签

sed 's/<[^>]*>//g;/^$/d;s/^[ ]*//' 1.txt
 

猜你喜欢

转载自blog.csdn.net/Mr_Bei/article/details/82884557