写于:2015-09-19		最近一次更新:2018-09-26

Intent:

忽略大小写 我想在使用 sed 命令的时候忽略大小写 不是使用 [aA][bB][cC] 这样的正则表达式 而是像 grep 的 -i 这样一个参数 可是在 man 手册里没有找到类似这样的参数,怎么办?

Oneway:

man sed 没找到需要的信息,注意 SEE ALSO 中的说明 info sed 提供了更全面详细的信息, 在 info sed 中可以找到 I 和 i , 这两个参数,就是用来忽略大小写的, 建议使用 I (大写),用法举例如下 有一个文件 myTestFile ,内容如下 [sman@Slackware:~/Desktop/test] $ cat myTestFile check hah heh test key Key kEy keY KEy KeY kEY KEY hello 我想用 sed 查看包含 key 的所有行, 不管 key 的三个字母是大写还是小写 [sman@Slackware:~/Desktop/test] $ sed -n '/key/I p' myTestFile key Key kEy keY KEy KeY kEY KEY 我想用 sed 把所有行中的 key 统统改成小写 [sman@Slackware:~/Desktop/test] $ sed 's/key/key/I g' myTestFile check hah heh test key key key key key key key key hello 确认无误后,使用 -i 参数把结果修改进 myTestFile 文件里 郑重声明: -i 参数不要与参数 -n 和动作 p 一起使用, 即 -i 与 -n p 不要一起出现,否则原文件中未改动的内容会丢失!!! [sman@Slackware:~/Desktop/test] $ sed 's/key/key/I g' myTestFile -i 来看一下改动后的 myTestFile 文件内容 [sman@Slackware:~/Desktop/test] $ cat myTestFile check hah heh test key key key key key key key key hello 全部改成小写的 key 了

Intent:

有多行满足条件时,在最后一个匹配行的后面增加内容

Oneway:

思路就是找到最后一个匹配行的行号, 然后在该行号后使用 a\ 来添加一行内容,本例 使用了在sed命令中引入外部命令或使用环境变量的方法来完成 “有多行满足条件时,在最后一个匹配行的后面增加内容”的目的

Details:

foo.txt的全部内容如下: aa1 bb1 cc1 bb2 dd1 bb3 ee1 ff1 foo.txt文件中,含有关键词 bb 的行有很多行 我只想在最后一个含有 bb 的那一行之后增加内容Hello Slackware 而不改变其他包含 bb 的行之后的内容 即把foo.txt的内容变成下面这样: aa1 bb1 cc1 bb2 dd1 bb3 Hello Slackware ee1 ff1 现在,用sed命令来实现这个目的 使用引入外部命令的方法: sed ''$(sed -n '/bb/ =' foo.txt | tail -1)'a\Hello Slackware' foo.txt 或者 使用环境变量的方法: MYVAR=$(sed -n '/bb/ =' foo.txt | tail -1);\ sed ''$MYVAR'a\Hello Slackware' foo.txt 备注: sed -n '/bb/ =' foo.txt | tail -1 打印所有包含bb的行的行号,用tail取出最后一个行号 使用'$(commands)'在sed命令中引入外部命令 使用'$ENVVAR'在sed命令中使用环境变量

Intent:

常见替换类场景举例,替换语法如下 sed '[address-range | pattern-range] s/original-string/replacement-string/[substitute-flags]' input-file

Oneway:

$ cat test.log you found me yes I found you #something was logging ... I lost pen ... alarm I lost desk ... alarm oh alarm I found a pen ... bugfix alarm I found a desk ... bugfix alarm ha alarm h alarm x alarm !!! I found a desk ... bugfix alarm ha alarm h ALArm x alarm !!! we are crazy ! where we are ? ls we are crazy ! LogDir="/home/user01/Download/testfiles" what a day (^_^) total 1234567 errors ! logging finshed ! 在指定的行范围内进行替换操作: sed '5,7 s/^..//' test.log 表示删除test.log文件的第5行至7行范围内的所有行的前2个字符(包含第5行和7行) 只对包含特定字符串的行执行替换操作: sed '/bugfix/ s/alarm/warning/g' test.log 表示如果sed读入的当前行里包含bugfix字符串则将这一行里的alarm替换成warning, 如果不包含bugfix那么即使这一行里有alarm也不会执行替换操作,会直接跳过当前行继续读入下一行 ! 表示当条件匹配时不执行命令,不匹配时执行命令 sed '/bugfix/ !s/alarm/warning/g' test.log 当行里包含bugfix时则不执行替换命令 当行里不包含bugfix时则执行替换命令 指定original-string在当前行出现的次序,只有在该行第n次出现的original-string才会被替换 sed 's/alarm/warning/3' test.log 表示把每行中第三次出现的alarm替换成warning,每行中第一次第二次第四次出现的alarm则不替换 substitute-flags 组合使用 sed 's/alarm/warning/I3g' test.log “I”表示忽略alarm的大小写, “3g”表示从每行的第三个匹配开始替换,直到每行的最后一个匹配,都替换掉 自定义替换命令的分界符 sed 'sDalarmDwarningDI3g' test.log 这是上一条命令的另一种写法,其实和上一条命令的效果一模一样, 紧跟在s后面的第一个单字节字符会被sed自动认定为替换命令的分界符 这个特性可方便的用于替换目录路径,而不用对冗长的路径分割符进行依次转义, 例如 sed 's/\/home\/user01\/Download\/testfiles/\/var\/test/g' test.log 可以写成sed 's#/home/user01/Download/testfiles#/var/test#g' test.log 把替换后的整行作为命令执行,并用命令执行后得到的结果替代原来的那一行内容 sed '10 s/ls/pwd/e' test.log 表示把第10行的ls替换成pwd后把该行作为命令执行, 且第10行的内容最终变成命令执行后的结果 使用花括号{}对命令操作部分进行嵌套,可构成条件”与“的关系 sed '5,11 {/found/{/desk/{s/ALArm/warning/g}}}' test.log 表示第5行到第11行同时包含found和desk的行才执行替换操作 当对{}里的命令使用!取反时,请务必把!放在{前面,而不是{}里面 对匹配到的行依次执行多个命令,命令之间用分号隔开 sed '5,11 {s/crazy/CRAZY/g;s/bug/BUG/g;s/BUGfix/Debug/g}' test.log 表示第5行到第11行有crazy则替换成CRAZY, 第5行到第11行有bug则替换为BUG, 第5行到第11行有BUGfix则替换为Debug 替换命令依次执行,后一个替换操作以上一个替换操作的结果为基础 这三个替换操作之间不存在约束关系即不存在条件“与”的关系 original-string中匹配到的内容可在replacement-string中用符号 & 引用 sed '8,17 s/^./#&/' test.log 表示在第8行到第17行的非空行行首添加#,实现快速注释的效果 (这里的 ^ 表示锚定行首) 分组替换,original-string中每个分组都以 \( 开始,以 \) 结束, 可在replacement-string中以 \number 的方式引用第number个分组匹配到的内容 sed '8,17 s/\(^.\)/#\1/' test.log 这个命令结果等效于上面符号&的用法 sed '8,17 s/\(we\)\(.*\)\(crazy\)\(.*\)where/#\1\2really \3\4/' test.log 表示在第8行到第17行寻找同时包含we和crazy和where的行,且对字符出现的顺序有要求 即we在crazy前面,crazy在where前面,也即出现顺序必须是先we再crazy再where, 然后在we前面添加#符号,在crazy的前面添加"really ",删除where,结束 sed '8,17 s/\(we\)\(.*\)\(crazy\)\(.*\)where/#& really/' test.log 注意,这句里的 & 表示分组1分组2分组3分组4以及where所构成的整体,不止代表分组1 在original-string中定义的分组只能在original-string和replacement-string中被引用, 在/match-string/ 匹配结构中定义的分组只能在match-string中被引用, sed -n '/\(we\).*\1/ {s/\(are\)\(.*\)\1/\1 really\2\1/;p}' test.log 这里第一个\1表示的是we,第二个\1和第三个\1和第四个\1表示的都是are replacement-string中特殊的替换标志 sed 's/alarm/\U&/ig' test.log sed 's/\(alarm\)\(.*\)\(x\)/\U\1\2\3/ig' test.log sed 's/\(alarm\)\(.*\)\(x\)/\U\1\E\2\3/ig' test.log \l (小写的 L ) 把紧跟在其后的一个字符当作小写字符来处理 \L 把跟在后面的所有字符都当作小写字符来处理,直到遇到\E为止 \u 把紧跟在其后的一个字符当作大写字符来处理 \U 把跟在后面的所有字符都当作大写字符来处理,直到遇到\E为止 \E 配合\L或者\U一起使用,表示结束\L或者\U的作用 sed 常用的其他动作命令 h:用模式空间中的内容覆盖保持空间 H:将模式空间中的内容追加至保持空间中 g:用保持空间中的内容覆盖模式空间 G:将保持空间中的内容追加至模式空间中 n:用匹配到的行的下一行的内容覆盖模式空间 N:将匹配到的行的下一行的内容追加至模式空间中 x:将模式空间中的内容与保持空间中的内容互换 d:清空模式空间,并读入下一行 D:删除模式空间中的第一行,不读入下一行 sed里正则表达式的一些基础用法如下: ^ 表示一行的开头,如:/^#/ 以#开头的匹配 $ 表示一行的结尾,如:/}$/ 以}结尾的匹配 \b 匹配一个字边界,即字与空格间的位置 \B 非字边界匹配 \< 表示词首,如:\<abc 表示以 abc 为首的词 \> 表示词尾,如:abc\> 表示以 abc 结尾的词 \{n\} 匹配确定的 n 次 \{n,\} 至少匹配 n 次 \{n,m\} 最少匹配 n 次且最多匹配 m 次 . 表示任何单个字符 ? 表示某个字符出现了0次或1次 * 表示某个字符出现了0次或多次 + 表示某个字符出现了1次或多次 [ ]字符集合 [abc] 表示匹配a或b或c, [a-zA-Z] 表示匹配所有的26个字符 [^a] 表示非a的字符

Intent:

使用sed模拟head,tail,tac,rev,paste,grep,uniq的功能,以及其他常见操作

Oneway:

模拟 head 的功能 sed '10q' test.log #显示文件前10行的内容 模拟 tail 的功能 sed ':a;$q;N;11,$D;ba' test.log #显示文件最后10行的内容 模拟 tac 的功能 sed -n '1!G;h;$p' test.log #倒序显示文件的所有行,最后一行成为第一行 模拟 paste 的功能 sed '$!N;s/\n/ /' test.log #将每两行用一个空格拼接成一行 模拟 grep 的功能 sed -n '/pen/ p' test.log #打印包含pen的行 sed '/pen/ !d' test.log #效果同上 模拟 uniq 的功能 sed '$!N;/^\(.*\)\n\1$/!P;D' test.log #删除相邻的重复行 以下是sed的一些常见操作 显示所有匹配行的上一行 sed -n '/found/{x;1!p;x};h' test.log 显示匹配行的上一行,若上一行也是匹配行则不显示 sed -n '/found/{x;/found/!{1!p};x};h' test.log 显示所有匹配行的下一行 sed -n ':a;/found/N;s/.*\n//p;ta' test.log 或者 sed -n ':a;/found/{N;s/.*\n//;p;ta}' test.log 显示匹配行的下一行,若下一行也是匹配行则不显示 sed -n ':a;/found/{N;s/.*\n//;{/found/!p};ta}' test.log 如果当前行以 m 结束,则将下一行并到当前行末尾,并用空格替换m 这里使用t来跳转标签的目的是当当前行内容发生了替换变化时反复处理当前行 当当前行无替换变化时则继续读入下一行 sed ':a;/m$/N;s/m\n/ /;ta' test.log 如果当前行以 I 开头,则将当前行并到上一行末尾,并用空格替换I sed ':a;N;s/\nI/ /;ta;P;D' test.log 为数字添加千分号 sed ':a;s/\B[0-9]\{3\}\>/,&/;ta' test.log 选择性的显示特定的某一行的内容 sed '10q;d' test.log #显示第10行的内容,处理大文件时比sed '10!d' test.log更快 sed -n ':a;$P;$q;N;11,$D;ba' test.log #显示倒数第10行的内容