linux 之sed用法

sed:Stream Editor文本流编辑,sed是一个“非交互式的”面向字符流的编辑器。在使用sed处理时,它把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接看用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕显示,接着处理下一行,不断重复直到文件末。默认情况下不会改变文件内容,除非使用了写入的命令,将内容更新。它的特点如下:

  • 1.它可以同时处理多个文件多行的内容(使用-e或者{})
  • 2.可以不对原文件改动,把整个文件输入到屏幕(不使用-i)
  • 3.可以把只匹配到模式的内容输入到屏幕上(使用-n)
  • 4.对原文件改动,但是不会再屏幕上返回结果(使用-i)

sed命令的语法格式:

  • sed的命令格式: sed [option] '[匹配模式] sed的内部命令' filename
  • sed的脚本格式:sed [option] -f 'sed script' filename

options:是可选的选择或参数
匹配模式:是可选的用于在文件中每一行进行匹配到模式,模式可以是正则,也可以是文件的行号
内部的命令:是可选的,但是两个单引号是必须的

sed命令的选项(option):

  • -n :只打印模式匹配的行
  • -e :直接在命令行模式上进行sed动作编辑,此为默认选项。。。使用多个-e可以进行多项编辑
  • -f :后跟脚本,是将sed的动作写在一个文件内,用–f filename 执行filename内的sed动作
  • -i :直接修改源文件内容,使用-i后不会再在终端输出文件内容
  • -r :支持扩展表达式
  • --follow-symlinks:
  • -l N, --line-length=N
  • --posix: disable all GNU extensions.
  • -s: consider files as separate rather than as a single continuous long stream.
  • -u,: load minimal amounts of data from the input files and flush the output buffers more often
  • -z, --null-data separate lines by NUL characters

sed的动作(sed command):

p:  打印匹配行,因为sed默认打印文件中所有的行,所以使用p后匹配行会被打印两次;p可以跟-n配合使用,用于只打印匹配行

    • sed -n '2p' learn_sed.txt 打印第二行
    • sed -n '/^first/!p' learn_sed.txt 打印非first开头的行,注意!的位置

a:在定位行号后插入新文本信息  i: 在定位行号前插入新文本信息

    • sed '/first/i nihao' learn_sed.txt或sed '/first/inihao' learn_sed.txt 在匹配到first的行前新增一行nihao,i选项后的空格会被忽略
    • sed '/first/i  nihao  22' learn_sed.txt 添加多行时,多行间使用 来换行, 后的空格是被识别的
    • sed '1i testdata' myfile 在文件的行首添加一行
    • sed '$a testdata' myfile 在文件的行尾追加一行,使用-a时,在匹配行后添加一行,a/i后的空格会被忽略

d:删除定位行,sed的删除操作是针对文件的行,如果想删除行中的某个字符,那就用替换

    • sed '/^#/d' myfile 删除以#开头的行
    • sed '/^#/!d' myfile 删除非#开头的行,即显示以#开头的行
    • sed '1d' myfile 删除第一行
    • sed '$d' myfile 删除最后一行
    • sed '2,4d' myfile 删除指定的2~4行
    • sed '/<line>/d' learn_sed.txt #<>是单词界定符,删除行中有line单词的行。。如果某一行为firstline,由于字符串中的line不是个单词,所以该行不会删除

s:使用替换模式替换相应模式,s后紧跟的符号为地址定界符,一般由3个组成,定界符可以是/$#@等特殊字符

    • sed '/second/s/^/my /' learn_sed.txt #在匹配行的行首添加my。(先匹配后替换)
    • sed '/first/s/$/ END/' learn_sed.txt #在匹配行的行尾添加 END。(先匹配后替换)
    • sed 's/second/my &/' learn_sed.txt #在匹配字符串的前边添加my ,其中&代表替换字符串即second
    • sed 's/second/& my/' learn_sed.txt #在匹配字符串的后边添加 my。
    • sed '/first/s/(.*)/1 END/' learn_sed.txt #使用正则方式在first所在行的行尾添加 END,其中()表示分组,.*表示任意字符,1引用第一个分组,在此处引用的是前边匹配的整行,然后在行尾添加 END。
    • sed -r 's/[0-9][0-9]$/&.5/' datafile //&代表在查找串中匹配到的内容
    • sed -r 's/(Mar)got/1ianne/g' datafile
    • sed 's/^/start /' learn_sed.txt 在每行行首添加start
    • sed 's/$/ end/' learn_sed.txt 在每行行尾添加end
    • sed '1,3s/^/#/' learn_sed.txt 在1到3行的行首添加#
    • sed -i '/second/s/22.1/10.12/' myfile   #匹配second的行,把22.1替换成10.12由于.号有特殊意义所有需要转义  
    • sed -i '/second/s/#//' myfile       #匹配second的行,把#替换成空,即去掉#号,也一般用作去掉#注释  
    • sed -i 's/root/(&)/g' myfile        #把root用括号括起来,&表示引用前面匹配的字符

w filename:写文本到一个文件,类似输出重定向 >,把正在用sed操作的文件内容写到另外一个文件中

    • sed 's/first/new first/w new.txt' learn_sed.txt       #w表示保存,new.txt文件名  
    • 执行该命令会将匹配行数据写入到新文件new.txt中

r filename:从另一个文件中读文本,类似输入重定向 <,读取一个文件到正在用sed操作的文件中

 从new2.txt中读取数据放在new.txt中的匹配行后

cat new.txt

  • new1
  • new2

cat new2.txt 

  • 222
  • 333

sed '/new1/r new2.txt' new.txt

  • new1
  • 222
  • 333
  • new2

sed '/new/r new2.txt' new.txt 

  • new1
  • 222
  • 333
  • new2
  • 222
  • 333

sed '1r new2.txt' new.txt

  • new1
  • 222
  • 333
  • new2

q:结束或退出sed

    • sed '5q' /etc/passwd#打印5行 

{}:使用{}实现多项编辑,不同编辑命令之间用分号

    • sed -n '1,2{p;=}' learn_sed.txt/sed -n '1,2{=;p}' learn_sed.txt #两个编辑命令相互约束生效,行号只打印到了2
    • sed -n '1,3!{=;p}' learn_sed.txt #使用!对前边的匹配模式取反,注意!的位置
    • sed -n '/^first/!{/^$/!p}' learn_sed.txt #打印非first开头以及非空的行,先过滤出非first开头的行,然后在此基础上过滤出空行
    • sed '/root/{s/bash/nologin/;s/0/1/g}' test   #匹配root的行,把bash替换成nologin,且把0替换成1  

n:从另一个文件中读文本下一行,并从下一条命令而不是第一条命令开始对其的处理

    • sed '/test/{ n; s/aa/bb/; }' example  如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,然后继续。

N:在数据流中添加下一行以创建用于处理的多行组

g:全局替换,当某行中有多个匹配项时,

    • 使用g可以全局匹配
    • 不使用g只匹配第一个
    • 使用2g会匹配第二个及第二个之后的匹配项
    • 使用2只匹配第二个
    • echo 'first line line line'|sed '/line/s/line/line22/' 输出为first line22 line line,只匹配了第一个
    • echo 'first line line line'|sed '/line/s/line/line22/g' 输出为first line22 line22 line22,全局匹配
    • echo 'first line line line'|sed '/line/s/line/line22/2g' 输出为first line line22 line22,匹配了第二个及以后的匹配项
    • echo 'first line line line'|sed '/line/s/line/line22/2' 输出为first line line22 line,只匹配了第二个

y:传送字符,替换单个字符,将字符替换为另一字符(不能对正则表达式使用y命令)

test_sed中的内容为:

    • 1234567890
    • 2345678901

执行sed 'y/1234567890/ABCDEFGHIJ/' test_sed的输出为:

    • ABCDEFGHIJ
    • BCDEFGHIJA

sed '1,10y/abcde/ABCDE/' example把1–10行内所有abcde转变为大写,注意,正则表达式元字符不能使用这个命令

!:反向选择

    • sed -r '3!d' /etc/hosts
    • sed -n '/^first/!p' learn_sed.txt 打印非first开头的行,注意!的位置
文件内容模式举栗

cat learn_sed.txt 

first line

second line

three line

last line

x x为行号

sed '2p' learn_sed.txt (打印 文件中的第二行,因为sed默认打印文件中所有的行,所以第二行会打印两次)

sed -n '2p' learn_sed.txt (使用-n可以只打印匹配到的行)

x,y 表示行号从x到y

sed -n '1,3p' learn_sed.txt

/pattern 查询包含模式的行

sed -n '/first/p' learn_sed.txt (打印文件中能够匹配first字符的行)

 

/pattern/,/pattern 查询两个模式之间的行

sed -n '/first/,/three/p' learn_sed.txt(打印从包含first的行开始到包含three的行)

 

sed '/first/,/second/d' learn_sed.txt(删除从包含first的行到包含second的行)

sed '/second/,/first/d' learn_sed.txt(删除从包含second的行到包含first的行,由于first在second之后,所以会删除second之后的行)

 

/pattern/,x 打印匹配pattern的行到x行之间的行,若包含pattern在x行之后,则只打印匹配pattern的行

sed -n '/second/,3p' learn_sed.txt(打印文件中从匹配second的行到第3行)

  • second line
  • three line

sed -n '/second/,1p' learn_sed.txt(若包含second的行在第1行之后,则只打印匹配到second的行)

  • second line
 

x,/pattern/ 打印x行到匹配pattern的行之间的行,x行在包含pattern的行之后,则只打印x行到文件最后一行的数据

sed -n '1,/second/p' learn_sed.txt(打印文件中从1行到匹配到second的行)

  • first line
  • second line

sed -n '3,/second/p' learn_sed.txt(第3行在匹配到second的行之后,所以只打印了第3行之后的数据)

  • three line
  • last line
 

x,y!

查询不包含指定行号x和y的行

sed -n '1,3!p' learn_sed.txt(打印不包含第一行到第三行数据的行)

sed -n '1!p' learn_sed.txt(打印不包含第一行数据的行)

     

sed命令中引用变量

1.sed命令里面没有默认的变量时可以把单引号改成双引号

  • var=first
  • echo 'first line'|sed "s/$var/test/"  #输出为test line
  • echo 'first line'|sed 's/$var/test/'  #输出为first line ${var}没有被识别

2.sed命令里面有默认的变量时,sed里面的语句必须用单引

  • sed "$a test" learn_sed.txt  #会报错sed: can't find label for jump to `est'
  • sed '$a test' learn_sed.txt   #在文件行尾新增一行test

3.sed命令里面有默认的变量时,sed里面的语句必须用单引,自己定义的变量需要加单引号。

  • sed '$a '$var'' learn_sed.txt #正确使用
  • sed '$a $var' learn_sed.txt #自定义变量没有被识别,必须使用单引号将变量括起来才行

sed 中的多项编辑

1.使用多个-e对单个文件进行多项操作,多项编辑命令分别生效,多项命令的执行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。

  • sed -e '/^first/d' -e '/^$/d' learn_sed.txt 先删除以first开头的行,再删除空行
  • sed -e '/second/d' -e '/first/d' learn_sed.txt或者使用sed -r '/first|second/d' learn_sed.txt  删除包含second或first的行
  • sed -n -e '1,3p' -e '=' learn_sed.txt或者sed -n -e '=' -e '1,3p' learn_sed.txt  两个命令分别生效,打印行号时显示了4

2.使用{}实现多项编辑,不同编辑命令之间用分号

  • sed -n '/^first/!{/^$/!p}' learn_sed.txt #打印非first开头以及非空的行
  • sed '{/first/d;/second/d}' learn_sed.txt  删除包含second或first的行
  • sed -n '1,2{p;=}' learn_sed.txt/sed -n '1,2{=;p}' learn_sed.txt #两个编辑命令相互约束生效,行号只打印到了2
  • sed -n '1,3!{=;p}' learn_sed.txt #使用!对前边的匹配模式取反,注意!的位置

3.多项编辑直接用分号分割

  • sed -r '1,3d; s/Hemenway/Jones/' datafile
  • sed -r '2s/WE/1000phone/g; 2s/Gray/YYY/g' datafile 等同于sed -r '2{s/WE/1000phone/g; s/Gray/YYY/g}' datafile

2)使用正则表达式、扩展正则表达式(必须结合-r选项)

^

匹配行首符合条件的内容,用法格式"^pattern"

  • #######sed的匹配模式支持正则表达式#####################  
  • sed -n '/r*t/p' /etc/passwd#打印匹配r有0个或者多个,后接一个t字符的行  
  • sed -n  '/.r.*/p' /etc/passwd#打印匹配有r的行并且r后面跟任意字符  
  • sed -n '/o*/p' /etc/passwd#打印o字符重复任意次  
  • sed -n '/o{1,}/p' /etc/passwd#打印o字重复出现一次以上  
  • sed -n '/o{1,3}/p' /etc/passwd#打印o字重复出现一次到三次之间以上  

$

匹配行尾符合条件的内容,用法格式"pattern$"

^$

空白行

.

匹配任意单个字符

*

匹配紧挨在前面的字符任意次(0,1,多次)

.*

匹配任意长度的任意字符

匹配紧挨在前面的字符0次或1次

 

{m,n}

匹配其前面的字符至少m次,至多n次

 

{m,}

匹配其前面的字符至少m次

 

{m}

精确匹配前面的m次{0,n}:0到n次

 

<

锚点词首----相当于 ,用法格式:<pattern

 

>

锚点词尾,用法格式:>pattern

 

<pattern>

单词锚点

 
 

分组,用法格式:pattern,引用1,2

 

[]

匹配指定范围内的任意单个字符

 

[^]

匹配指定范围外的任意单个字符

 

[:digit:]

所有数字, 相当于0-9, [0-9]---> [[:digit:]]

 

[:lower:]

所有的小写字母

 

[:upper:]

所有的大写字母

 

[:alpha:]

所有的字母

 

[:alnum:]

相当于0-9a-zA-Z

 

[:space:]

空白字符

 

[:punct:]

所有标点符号

 
sed正则表达式匹配,各种括号的转义和不转义
[ ] 需要匹配的时候,需要转义(这个是叛徒)
echo "[ ]"|sed 's/[.*]/aaa/g'
( ) 需要匹配的时候,不要转义
$echo "( )"|sed 's/( )/c/g'
{ } 需要匹配的时候,不要转义
$echo "{ }"|sed 's/{ }/c/g'
使用{ }作为特殊字符时候,需要转义
$echo "333"|sed 's/[0-9]{3}/ccc/g'
当需要适配符,需要使用1来替换正则表达式的对应参数时:
不能写(regrexxxx)
要写(regrexxxx)
$echo "{1234567}"|sed 's/{([0-9]*)}/1/g'
+ *
在做为特别字符时候+必须转义为+
而*则不需要
echo "ccc"| sed 's/c*/aaa/g'#正确
echo "ccc"| sed 's/c*/aaa/g'#错误
echo "ccc"| sed 's/c+/aaa/g'#错误
echo "ccc"| sed 's/c+/aaa/g'#正确
 

sed的经典例子及常用操作

1.cat file.txt的输出如下,期望处理以下文件内容,将域名取出并进行计数排序 

内容如下:

期望结果如下,输出内容为域名的出现的次数 域名:  

实现方式:

  • cat file.txt | sed -e ' s/http:////' -e ' s//.*//' | sort | uniq -c | sort -rn  
  • awk -F/ '{print $3}' file.txt |sort -r|uniq -c|awk '{print $1" ",$2}'  

2.用grep结合sed取出网卡的ip地址  

 ifconfig | grep -B1 "inet addr" |grep -v "--" |sed -n -e 'N;s/eth[09].* .*addr:[09]{1,3}.[09]{1,3}.[09]{1,3}.[09]{1,3}.*/1 2/p'  

3.批量替换多个文件中的字符串 

sed -i "s/原字符串/新字符串/g" `grep 原字符串 -rl 所在目录`

其中,-i 表示inplace edit,就地修改文件,-r 表示搜索子目录,-l 表示输出匹配的文件名,这个命令组合很强大,要注意备份文件。

4.替换命令中的注意点

  • $ sed 's/test/mytest/g' example  在整行范围内把test替换为mytest。如果没有g标记,则只有每行第一个匹配的test被替换成mytest。
  • $ sed -n 's/^test/mytest/p' example  (-n)选项和p标志一起使用表示只打印那些发生替换的行。也就是说,如果某一行开头的test被替换成mytest,就打印它。
  • $ sed 's/^192.168.0.1/&localhost/'example  &符号表示替换换字符串中被找到的部份。所有以192.168.0.1开头的行都会被替换成它自已加localhost,变成192.168.0.1localhost。
  • $ sed -n 's/(love)able/1rs/p' example  love被标记为1,所有loveable会被替换成lovers,而且替换的行会被打印出来。
  • $ sed 's#10#100#g' example  不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有10替换成100。

5.使用|同时匹配两种模式

  • sed -r '/first|second/d' learn_sed.txt或者sed -nr '/first|second/p' learn_sed.txt
  • sed -nr '/^(patt1|patt2)$/p'  匹配整条行
  • sed -n '/^(patt1|patt2)$/p' 也可以删除-r并添加转义符

6.删除/替换 所有匹配结果中的第一个

  • sed -i '0,/happy/{/happy/d}' test.txt    #删除从0行到happy行里面的happy行,相当于删除第一个happy行
  • sed -i '0,/happy/{/happy/s/$/aa/}' test.txt    #先匹配从0行到happy行,然后找到有happy的行进行替换
7.sed替换多个空格
  1. echo 'a c b d'|sed 's/[ ]+/ /g'
  2. echo 'a c b d'|sed -e 's/[[:space:]][[:space:]]*/ /g'
  3. echo 'a c b d'|sed -i 's/[ ][ ]*/ /g'
1)[:space] 即为空格
2)*号代表0个或多个,+代表一个或多个
 
8.获取文件中case id
文件log_${1}_bak为:
Only in h264_fpga/h264_random/case_2711: stream_0.yuv_0
Only in h264_fpga/h264_random/case_6093: stream_0.yuv_276248
Files h264_cmodel/h264_random/case_6342/stream_0.yuv and h264_fpga/h264_random/case_6342/stream_0.yuv differ
Only in h264_fpga/h264_random/case_6342: stream_0.yuv_0
Only in h264_fpga/h264_random/case_6342: stream_0.yuv_450
Only in h264_fpga/h264_random/case_6342: stream_0.yuv_475
Files h264_cmodel/h264_random/case_6443/stream_0.yuv and h264_fpga/h264_random/case_6443/stream_0.yuv differ
Only in h264_cmodel/h264_random/case_7120: stream_0.yuv
Only in h264_cmodel/h264_random/case_7156: stream_0.yuv
  • cat log_${1}_bak|sed 's/.*case_//g'|sed 's/[^0-9].*stream_0.yuv.*$/ /g'|sort|uniq|tr " " " ">log_${1}
  • cat log_${1}_bak|awk -F"case_" '{print $2}'|awk -F"[:/]" '{print $1}'|sort|uniq|tr " " " ">log_${1}
  • cat log_${1}_bak|sed 's#.*case_([0-9].*)[:/].*$#1#g'|sort|uniq|tr " " " ">log_${1} #使用1来替换正则表达式的对应参数
9.sed/tr替换换行符为空格
1 sed 命令 sed命令的输出结尾有换行符
sed ':a;N;$!ba;s/ / /g' 这将在一个循环里读取整个文件,然后将换行符替换成一个空格。
说明:
  • 通过 :a创建一个标记
  • 通过N追加当前行和下一行到模式区域
  • 如果处于最后一行前,跳转到之前的标记处。 $!ba ($! 意思是不在最后一行做这操作 (最后一行就被当成最后的一行).
  • 最后置换操作把模式区域(就是整个文件)的每一个换行符换成一个空格。
示例追加:
$ echo -e "1 2" | sed ':a;N;$!ba;s/ / /g' 输出为:1 2
sed ':label;N;s/ / /;b label' 更深处的参考:https://my.oschina.net/shelllife/blog/118337
 
2 tr命令 tr命令的输出结尾没有换行符
cat country.txt | tr " " " "

扩展知识:

  • Ubuntu:sed -i '2d' test.txt
  • Mac:sed -i '' '3d' test.txt    Mac中必须使用'',否则报错sed: 1: "test.txt": undefined laebl 'est.txt',原因是mac强制要求备份,使用''可以只保留一份
  • 使用&表示替换字符串 sed 's/a/&i/' aaa.txt ,将每行第一个被匹配到的a都被替换为ai
  • 紧挨着s命令的符号被认为是分割符 sed 's#a#i#' aaa.txt 分割符为#

参考:

原文地址:https://www.cnblogs.com/mianbaoshu/p/12067409.html