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 |
在定位行号前插入新文本信息 |
|||||||||
c\ |
用新文本替换定位文本 |
|||||||||
d |
删除定位行 sed的删除操作是针对文件的行,如果想删除行中的某个字符,那就用替换 |
|
||||||||
s |
使用替换模式替换相应模式 s后紧跟的符号为地址定界符,一般由3个组成,定界符可以是/$#@等特殊字符 |
|
||||||||
w filename |
写文本到一个文件,类似输出重定向 > 把正在用sed操作的文件内容写到另外一个文件中 |
|
||||||||
r filename |
从另一个文件中读文本,类似输入重定向 < 读取一个文件到正在用sed操作的文件中 |
|
||||||||
q |
|
sed '5q' /etc/passwd#打印前5行 | ||||||||
l |
显示与八进制ACSII代码等价的控制符 |
|||||||||
{} |
使用{}实现多项编辑,不同编辑命令之间用分号 |
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 sed -n '/line/{n;s/line/line22/p}' learn_sed.txt 输出为second line22\nlast line22,第一行与第三行被跳过 |
||||||||
N |
在数据流中添加下一行以创建用于处理的多行组 |
|||||||||
g |
全局替换,当某行中有多个匹配项时,
|
|
||||||||
y |
传送字符,替换单个字符,将字符替换为另一字符(不能对正则表达式使用y命令) |
test_sed中的内容为:
执行sed 'y/1234567890/ABCDEFGHIJ/' test_sed的输出为:
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行)
sed -n '/second/,1p' learn_sed.txt(若包含second的行在第1行之后,则只打印匹配到second的行)
|
|||||||||
x,/pattern/ 打印x行到匹配pattern的行之间的行,若x行在包含pattern的行之后,则只打印x行到文件最后一行的数据 |
sed -n '1,/second/p' learn_sed.txt(打印文件中从1行到匹配到second的行)
sed -n '3,/second/p' learn_sed.txt(第3行在匹配到second的行之后,所以只打印了第3行之后的数据)
|
|||||||||
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" |
|
$ |
匹配行尾符合条件的内容,用法格式"pattern$" |
|
^$ |
空白行 |
|
. |
匹配任意单个字符 |
|
* |
匹配紧挨在前面的字符任意次(0,1,多次) |
|
.* |
匹配任意长度的任意字符 |
|
\? |
匹配紧挨在前面的字符0次或1次 |
|
\{m,n\} |
匹配其前面的字符至少m次,至多n次 |
|
\{m,\} |
匹配其前面的字符至少m次 |
|
\{m\} |
精确匹配前面的m次\{0,n\}:0到n次 |
|
\< |
锚点词首----相当于 \b,用法格式:\<pattern |
|
\> |
锚点词尾,用法格式:\>pattern |
|
\<pattern\> |
单词锚点 |
|
分组,用法格式:pattern,引用\1,\2 |
||
[] |
匹配指定范围内的任意单个字符 |
|
[^] |
匹配指定范围外的任意单个字符 |
|
[:digit:] |
所有数字, 相当于0-9, [0-9]---> [[:digit:]] |
|
[:lower:] |
所有的小写字母 |
|
[:upper:] |
所有的大写字母 |
|
[:alpha:] |
所有的字母 |
|
[:alnum:] |
相当于0-9a-zA-Z |
|
[:space:] |
空白字符 |
|
[:punct:] |
所有标点符号 |
sed的经典例子及常用操作
1.cat file.txt的输出如下,期望处理以下文件内容,将域名取出并进行计数排序
内容如下:
- http://www.baidu.com/index.<a target="_blank" href="http://www.2cto.com/kf/qianduan/css/" class="keylink" style="border:none; padding:0px; margin:0px; color:rgb(51,51,51); text-decoration:none; font-size:14px">html</a>
- http://www.baidu.com/1.html
- http://post.baidu.com/index.html
- http://mp3.baidu.com/index.html
- http://www.baidu.com/3.html
- http://post.baidu.com/2.html
期望结果如下,输出内容为域名的出现的次数 域名:
实现方式:
- 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"\t",$2}'
2.用grep结合sed取出网卡的ip地址
ifconfig | grep -B1 "inet addr" |grep -v "\-\-" |sed -n -e 'N;s/eth[0−9].*\n.*addr:[0−9]{1,3}\.[0−9]{1,3}\.[0−9]{1,3}\.[0−9]{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并添加转义符
扩展知识:
- 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 分割符为#
参考: