sed 是一种在线编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有 改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
参数说明:
参数说明-e以选项中指定的script来处理输入的文本文件-f以选项中指定的script文件来处理输入的文本文件-h或–help显示帮助-n仅显示script处理后的结果-V或–version 显示版本信息动作说明:
动作说明a新增,a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)p打印,通常 p 会与参数 sed -n 一起运行c取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行d删除,删除选择的行;D删除模板块的第一行i插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);s取代,通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!h拷贝模板块的内容到内存中的缓冲区;H追加模板块的内容到内存中的缓冲区;g获得内存缓冲区的内容,并替代当前模板块中的文本;G获得内存缓冲区的内容,并追加到当前模板块文本的后面;l列表不能打印字符的清单;n读取下一个输入行,用下一个命令处理新的行而不是用第一个命令;N追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码;p打印模板块的行。 P(大写) 打印模板块的第一行;q退出Sed;rfile 从file中读行;blable 分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾;tlabel if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾;Tlabel 错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾;wfile 写并追加模板块到file末尾;Wfile 写并追加模板块的第一行到file末尾;!表示后面的命令对所有没有被选定的行发生作用;=打印当前行号;#把注释扩展到下一个换行符以前;sed替换标记:
g表示行内全面替换;p表示打印行;w表示把行写入一个文件;x表示互换模板块中的文本和缓冲区中的文本;y表示把一个字符翻译为另外的字符(但是不用于正则表达式);\1子串匹配标记;&已匹配字符串标记;sed元字符集:
^匹配行开始,如:/^sed/匹配所有以sed开头的行;$匹配行结束,如:/sed$/匹配所有以sed结尾的行;.匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d;*匹配0个或多个字符,如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行;[]匹配一个指定范围内的字符,如/[ss]ed/匹配sed和Sed;[^]匹配一个不在指定范围内的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行;\(…\)匹配子串,保存匹配的字符,如s/(love)able/\1rs,loveable被替换成lovers;&保存搜索字符用来替换其他字符,如s/love/&/,love这成love;<匹配单词的开始,如:/\>匹配单词的结束,如/love>/匹配包含以love结尾的单词的行;x{m}重复字符x,m次,如:/0{5}/匹配包含5个0的行;练习:
①#全局替换:g sed 's/book/books/g' file #/g 标记会替换每一行中的所有匹配 echo sksksksksksk | sed 's/sk/SK/2g' #需要从第N处匹配开始替换时,可以使用 /Ng [root@zt ~]# echo sksksksksksk | sed 's/sk/SK/2g' skSKSKSKSKSK ②#定界符 命令中字符 / 在sed中作为定界符使用,也可以使用任意的定界符 sed 's:test:TEXT:g' ---> : : : sed 's|test|TEXT|g' ---> | | | #定界符出现在样式内部时,需要进行转义: #组合多个表达式 sed 's/\/bin/\/usr\/local\/bin/g' sed '表达式' | sed '表达式' sed '表达式; 表达式' ③#删除:d sed '/^$/d' file #删除空白行 sed '2d' file #删除第二行 sed '2,$d' file #删除第二行到最后一行 sed '$d' file #删除最后一行 sed '/^test/'d file #删除以test开头的行 ④#已匹配字符串标记& #正则表达式 \w\+ 匹配每一个单词,使用 [&] 替换它,& 对应于之前所匹配到的单词 [root@zt ~]# echo "this is a test line" | sed 's/\w\+/[&]/g' [this] [is] [a] [test] [line] #所有以192.168.0.1开头的行都会被替换成它自已加localhost: [root@zt ~]# sed 's/^192.168.0.1/&localhost/' file hello this is a test line 192.168.0.1localhost ⑤#子串匹配标记\1 #love被标记为1,所有loveable会被替换成lovers,并打印出来 sed -n 's/\(love\)able/\1rs/p' file [root@zt ~]# echo this is digit 7 in a number | sed 's/digit\([0-9]\)/\1/' this is digit 7 in a number [root@zt ~]# echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/' this is 7 in a number #命令中 digit 7,被替换成了 7。样式匹配到的子串是 7,\(..\) 用于匹配子串, 对于匹配到的第一个子串就标记为 \1,依此类推匹配到的第二个结果就是 \2 [root@zt ~]# echo aaa BBB | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/' BBB aaa [root@zt ~]# echo aaa BBB | sed 's/\([a-z]\+\) \([A-Z]\+\)/\1/' aaa [root@zt ~]# echo abcd | sed 's/\([a-z]\+\)\([a-z]\+\)\([a-z]\+\)\([a-z]\+\)/\2/' b [root@zt ~]# echo abcd | sed 's/\([a-z]\+\)\([a-z]\+\)\([a-z]\+\)\([a-z]\+\)/\1\2/' ab ⑥#多点编辑,e #-e选项允许在同一行里执行多条命令 sed -e '1,5d' -e 's/test/check/' file #上面sed表达式的第一条命令删除1至5行,第二条命令用check替换test。 命令的执行顺序对结果有影响。如果两个命令都是替换命令, 那么第一个替换命令将影响第二个替换命令的结果 ⑦#选定行的范围:,(逗号) #所有在模板test和check所确定的范围内的行都被打印 sed -n '/test/,/check/p' file #打印从第5行开始到第一个包含以mail开始的行之间的所有行: [root@zt ~]# sed -n '5,/^mail/p' /etc/passwd lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin #对于模板test和west之间的行,每行的末尾用字符串aaa bbb替换 sed '/test/,/west/s/$/aaa bbb/' file ⑧#转换:y #把1~10行内所有abcde转变为大写,注意,正则表达式元字符不能使用这个命令 sed '1,10y/abcde/ABCDE/' file ⑨#从文件读入:r #file里的内容被读进来,显示在与test匹配的行后面,如果匹配多行, 则file的内容将显示在所有匹配行的下面 sed '/test/r file' filename ⑩#写入文件:w #在example中所有包含test的行都被写入file里 sed -n '/test/w file' example ⑾#追加(行下):a #将 this is a test line 追加到 以test 开头的行后面 sed '/^test/a\this is a test line' file sed -i '2a\this is a test line' test.conf #第2行之后插入 ⑿#插入(行上) #i\命令 将 this is a test line 追加到以test开头的行前面 sed '/^test/i\this is a test line' file sed -i '5i\this is a test line' test.conf ⒀#下一个:n #如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行, 然后继续 sed '/test/{ n; s/aa/bb/; }' file测试:
1.以行为单位的删除
①将 /etc/passwd 的内容列出并且列印行号,同时,请将第 2~5 行删除! ②只要删除第 2 行 ③要删除第 3 到最后一行
2.以行为单位的新增
①在第三行后加上newline字样 ②在第三行前加上newline字样 ③在第二行后面加入两行字,例如newline1 和 newline2 注意:每一行之间都必须要以反斜杠『 \ 』来进行新行的添加
3.以行为单位的替换与显示
①将/etc/passwd中第2-5行的内容取代成为newline ②仅列出 /etc/passwd 文件内的第 5-7 行 ③搜索 /etc/passwd有root关键字的行 如果root找到,除了输出所有行,还会输出匹配行。使用-n的时候将只打印包含模板的行。
4.数据的搜寻并删除
①删除/etc/passwd所有包含root的行,其他行输出 ②删除/etc/passwd中第5-7行,其他行输出
5.数据的搜寻并执行命令
①搜索/etc/passwd,找到root对应的行,把bash替换为blueshell,再输出这行
6.数据的搜寻并替换命令
除了整行的处理模式之外, sed 还可以用行为单位进行部分数据的搜寻并代。 sed 's/要被取代的字串/新的字串/g’
7.多个命令同时编辑
①一条sed命令,删除/etc/passwd第3行到第五行的数据,并把sbin替换为bin 命令执行后: 注意:-e表示多点编辑,第一个编辑命令删除/etc/passwd第第3行到第五行的数据,第二条命令把sbin替换为bin。
8.直接修改文件内容(危险动作)
sed 可以直接修改文件的内容,不必使用管道命令或数据流重导向! 不过由于这个动作会直接修改到原始的文件,所以千万不要随便拿系统配置来测试!
/etc/passwd中的练习,为更简洁的表示 只取后三行
sshd❌74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin ZT❌1000:1000::/home/ZT:/bin/bash ALICE❌1001:1001::/home/ALICE:/bin/bash
删除文件每行的第一个字符 [root@zt ~]# sed 's/\(.\)\(.*\)/\2/' /etc/passwd | tail -3 shd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin T:x:1000:1000::/home/ZT:/bin/bash LICE:x:1001:1001::/home/ALICE:/bin/bash 删除文件每行的第二个字符 [root@zt ~]# sed 's/\(.\)\(.\)\(.*\)/\1\3/' /etc/passwd |tail -3 shd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin Z:x:1000:1000::/home/ZT:/bin/bash AICE:x:1001:1001::/home/ALICE:/bin/bash 删除文件每行的最后一个字符 [root@zt ~]# sed 's/\(.*\)\(.\)/\1/' /etc/passwd | tail -3 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologi ZT:x:1000:1000::/home/ZT:/bin/bas ALICE:x:1001:1001::/home/ALICE:/bin/bas 删除文件每行的倒数第二个字符 [root@zt ~]# sed 's/\(.*\)\(.\)\(.\)/\1\3/' /etc/passwd | tail -3 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologn ZT:x:1000:1000::/home/ZT:/bin/bah ALICE:x:1001:1001::/home/ALICE:/bin/bah [root@zt ~]# 删除文件每行的第二个单词 [root@zt ~]# sed 's/\([a-Z]\+\)\([^a-Z]\+\)\([a-Z]\+\)\(.*\)/\1\2\4/' /etc/passwd | tail -3 sshd::74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin ZT::1000:1000::/home/ZT:/bin/bash ALICE::1001:1001::/home/ALICE:/bin/bash [root@zt ~]# 删除文件每行的倒数第二个单词 [root@zt ~]# sed -r 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]*$)/\1\2\4\5/' /etc/passwd| tail -3 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd://nologin ZT:x:1000:1000::/home/ZT://bash ALICE:x:1001:1001::/home/ALICE://bash 删除文件每行的最后一个单词 [root@zt ~]# sed -r 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]*$)/\1\2\3\4/' //etc/passwd | tail -3 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/ ZT:x:1000:1000::/home/ZT:/bin/ ALICE:x:1001:1001::/home/ALICE:/bin/ [root@zt ~]# 交换每行的第一个字符和第二个字符 [root@zt ~]# sed -r 's/(.)(.)(.*)/\2\1\3/' /etc/passwd | tail -3 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin TZ:x:1000:1000::/home/ZT:/bin/bash LAICE:x:1001:1001::/home/ALICE:/bin/bash [root@zt ~]# 交换每行的第一个字符和第二个单词 [root@zt ~]# sed 's/\(^[a-Z0-9]\)\([a-Z0-9]*[^a-Z0-9]\{1,\}\)\([a-Z0-9]\{1,\}\)/\3\2\1/g' /etc/passwd |tail -3 xshd:s:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin xT:Z:1000:1000::/home/ZT:/bin/bash xLICE:A:1001:1001::/home/ALICE:/bin/bash [root@zt ~]# 交换每行的第一个单词和最后一个单词 [root@zt ~]# sed -r 's/([a-Z]+)([^a-Z]+)(.*)([^a-Z]+)([a-Z]+)([^a-Z]*$)/\5\2\3\4\1\6/' /etc/passwd | tail -3 nologin:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/sshd bash:x:1000:1000::/home/ZT:/bin/ZT bash:x:1001:1001::/home/ALICE:/bin/ALICE [root@zt ~]# 删除一个文件中所有的数字 [root@zt ~]# sed 's/[0-9]//g' /etc/passwd | tail -3 sshd:x:::Privilege-separated SSH:/var/empty/sshd:/sbin/nologin ZT:x::::/home/ZT:/bin/bash ALICE:x::::/home/ALICE:/bin/bash [root@zt ~]# 删除每行开头的所有空格 [root@localhost ~]# sed -r 's/^ +//g' /etc/grub2.cfg ......(省略) ### BEGIN /etc/grub.d/41_custom ### if [ -f ${config_directory}/custom.cfg ]; then source ${config_directory}/custom.cfg elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then source $prefix/custom.cfg; fi ### END /etc/grub.d/41_custom ### [root@localhost ~]# 用制表符替换文件中出现的所有空格 [root@zt ~]# sed -r 's/ +/\t/g' /etc/passwd | tail -3 sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin ZT:x:1000:1000::/home/ZT:/bin/bash ALICE:x:1001:1001::/home/ALICE:/bin/bash [root@zt ~]# 把所有大写字母用括号()括起来 [root@zt ~]# sed -r 's/([A-Z])/(\1)/g' /etc/passwd | tail -3 sshd:x:74:74:(P)rivilege-separated (S)(S)(H):/var/empty/sshd:/sbin/nologin (Z)(T):x:1000:1000::/home/(Z)(T):/bin/bash (A)(L)(I)(C)(E):x:1001:1001::/home/(A)(L)(I)(C)(E):/bin/bash [root@zt ~]# 打印每行3次 [root@zt ~]# sed 'p;p' /etc/passwd | tail -3 ALICE:x:1001:1001::/home/ALICE:/bin/bash ALICE:x:1001:1001::/home/ALICE:/bin/bash ALICE:x:1001:1001::/home/ALICE:/bin/bash [root@zt ~]# 隔行删除 [root@zt ~]# sed '0~2 {=;d}' /etc/passwd root:x:0:0:root:/root:/bin/bash 2 daemon:x:2:2:daemon:/sbin:/sbin/nologin 4 ...... ZT:x:1000:1000::/home/ZT:/bin/bash 20 [root@zt ~]# 把文件从第1行到第2行复制到第4行后面 sed '1h;2,2H;4G' sed.txt sed '1{h;d};2,2{H;d};4g' sed.txt [root@localhost ~]# more sed.txt hello linux hi world [root@localhost ~]# sed '1h;2,2H;4G' sed.txt hello linux hi world hello linux [root@localhost ~]# 只显示每行的第一个单词 [root@zt ~]# sed 's/\([a-Z]\+\)\([^a-Z]\+\)\(.*\)/\1/' /etc/passwd | tail -3 sshd ZT ALICE [root@zt ~]# 打印每行的第一个单词和第三个单词 [root@zt ~]# sed 's/\([a-Z]\+\)\([^a-Z]\+\)\([a-Z]\+\)\([^a-Z]\+\)\([a-Z]\+\)\([^a-Z]\+\)\(.*\)/\1\t\5/' /etc/passwd | tail -n 3 sshd Privilege ZT home ALICE home [root@zt ~]# 将格式为 mm/yy/dd 的日期格式换成 mm;yy;dd [root@zt ~]# date '+%m/%y/%d' |sed 's#/#; #g' 10; 18; 31 [root@zt ~]#21.只显示IP地址
[root@zt ~]# ifconfig | egrep 'inet' | grep -v 'inet6' inet 192.168.163.135 netmask 255.255.255.0 broadcast 192.168.163.255 inet 127.0.0.1 netmask 255.0.0.0 [root@zt ~]# ifconfig | egrep 'inet' | grep -v 'inet6' | sed 's/^.*inet//g' 192.168.163.135 netmask 255.255.255.0 broadcast 192.168.163.255 127.0.0.1 netmask 255.0.0.0 [root@zt ~]# ifconfig | egrep 'inet' | grep -v 'inet6' | sed 's/^.*inet//g' | sed 's/netmask.*$//g' 192.168.163.135 127.0.0.122.去掉ssh配置文件中的带#行和空行
more /etc/ssh/sshd_config more /etc/ssh/sshd_config | sed 's/#.*$//g' more /etc/ssh/sshd_config | sed 's/#.*$//g' | sed '/^$/d'