Linux - sed命令

简介

sed是强大的非交互式的流编辑器, 支持正则表达式, 可直接在控制台命令行或shell脚本中对文本进行过滤, 搜索, 查找, 替换, 插入或删除操作,而不用像vim那样打开文本. sed默认情况下不会修改文件 除非使用shell重定向来保存输出结果.

工作流程

sed逐行处理文件,并打印处理结果. 流程如下:

  1. 读取要处理的程序脚本 --- SED PROGRAM

  2. 读取一行输入文件内容 --- INPUT : filename line 1

  3. 将其复制到一个临时缓冲区,称为模式空间(pattern space)中, --- PATTERN

  4. 在模式空间中, 根据提供的命令进行匹配, 并修改数据 --- COMMAND, MATCHED REGEX REGISTERS

  5. 将处理结果输出到屏幕(除非有命令删除或取消打印) --- PATTERN

  6. 结束本轮循环 --- END - OF - CYCLE

  7. 继续读取下一行数据, 重复以上过过程 直到所有数据处理完毕. ---INPUT : filename line 2

语法

sed OPTIONS... [SCRIPT, -f SCRIPT-FILE] [INPUTFILE...] 

常用选项/参数

选项/参数 说明
-n, --quiet, --silent 安静模式,在一般情况所有的 stdin 都会输出到屏幕上, 加入-n 后只打印被sed处理的行
-i[SUFFIX], --in-place[=SUFFIX] 直接修改输入文件的内容,不在屏幕上输出, 如提供后缀SUFFIX 则会在当前目录自动备份源输入文件
-e script, --expression=script 以选项中的指定的script来处理输入文件
-E, -r, --regexp-extended 使用扩展正则
-f script-file, --file=script-file 以选项中指定的script文件来处理输入文件
-s, --separate 将多个文件分别单独处理
-u, --unbuffered 从多个输入文件中加载最少数量的数据, 更频繁地刷新输出缓存
-z --null-data 默认\n分隔行, 如果有-z, 则按空字符分隔每行

sed操作命令

操作命令 说明
a \ append 在指定行后添加文本 \为内嵌文本换行
c \ 用新文本修改替换选定的文本 \为内嵌文本换行
i \ insert 在指定行之前插入文本 \为内嵌文本换行
p 输出当前模式空间的内容
d 删除模式空间内容, 开启新一轮循环 => 删除选中行
x 交换保持空间(hold space)和模式(pattern space)的内容
g 替换模式空间中的内容为保持空间中的内容
G 在模式空间换行, 将保持空间里的内容追加到模式空间
h 替换保持空间中的内容为模式空间中的内容
H 在保持空间换行, 将模式空间里的内容追加到保持空间
w 将当前模式空间内容写入文件
W 将当前模式空间第一行写入文件
I 列出非打印字符
n, N 读取/追加下一行输入, 从下一行开始处理
q 立即结束, 不会再处理其他输入
r 从文件中读行
! 对所选行除外的所有行应用命令
s 替换指定字符
--debug debug 显示处理的全过程

sed寻址类命令(Addresses)

如果没有地址, sed命令将应用与所有输入行;

给定一个地址, sed仅会执行与该地址匹配的行.

命令 说明
number 匹配指定行, 如果有多个输入文件, 行号会累加, 除非使用-s选项
first~step 从first行开始按步长匹配行, addr1 为0时, 从step行开始, 按步长匹配
$ 匹配最后一行
/regexp/ 按正则匹配行
\cregexpc 表示匹配正则那一行,通过\c 和 c 之间的正则来匹配,c 可以是任一字符
addr1, addr2 匹配从addr1 到 addr2的行, 起始行addr1总会被匹配执行, 无论结束行addr2是否匹配, 即使addr2可能比addr1小; 如果addr2是正则表达式, addr2也不会与addr1匹配冲突.(见实例 13)
0, addr2 仅当addr2为正则时有效, 起始行, 结束行都按addr2规则进行匹配, 如果开始第一行就命中addr2的规则, 则处理第一行后其余行就无法命中匹配, 而不会像addr1, addr2那样匹配addr1后,继续检测结束行addr2的匹配规则 (见实例 14)
addr1, +N 从addr1匹配的行开始 到addr1+N 行的范围
addr1, ~N 从addr1匹配的行开始, 逐行匹配, 直到行数为N的倍数

使用示例

$ cat input.txt 
unix is great os. unix is opensource. unix is free os.
learn operating system.
unix linux which one you choose.
unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
  1. s替换

    # 默认每一行只会匹配一次, 替换后便开始读取下一行(开启新一轮循环)
    
    $ sed 's/unix/Linux/' input.txt 
    Linux is great os. unix is opensource. unix is free os.
    learn operating system.
    Linux linux which one you choose.
    Linux is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
    
    #加入g命令, 进行全局修改
    $ sed 's#unix#linux#g' input.txt 
    linux is great os. linux is opensource. linux is free os.
    learn operating system.
    linux linux which one you choose.
    linux is easy to learn.linux is a multiuser os.Learn linux .linux is a powerful.
    

    由于是在模式空间中操作并打印, 输出结果实际上并没有更改原输入文件(input file)

    $ cat input.txt 
    unix is great os. unix is opensource. unix is free os.
    learn operating system.
    unix linux which one you choose.
    unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
    
  1. d删除行

    $ sed '2,$d' input.txt > output.txt #只保留第一行      ,表示范围
    $ sed '1d;3d' input.txt > output.txt #删除第1和第3行,  ;表示分隔
    $ sed '/learn/d' input.txt > output.txt  #删除包含learn的行 
    
    
  1. i, a, c\ 插入替换文本

    # i 在第一行前添加2行
    $ seq 5 | sed '1i 100\  
    > 200' > output.txt 
    
    #显示结果
    $ cat output.txt 
    100
    200
    1
    2
    3
    4
    5 
    
    # a 在第三行后追加2行
    $ seq 5 | sed '3a 100\
    200' > output.txt
    
    #显示结果
    $ cat output.txt 
    1
    2
    3
    100
    200
    4
    5
    
    # c 将第二行替换成200
    seq 5 | sed '2c200' > output.txt
    #显示结果
    $ cat output.txt 
    1
    200
    3
    4
    5
    
  1. 重定向到输出文件

    如果没有指定输入文件 或输入文件是 - , sed会过滤处理标准输入内容, 下面的3行命令等效

    $ sed 's/unix/Linux/' input.txt > output.txt
    $ sed 's/unix/Linux/' < input.txt > output.txt
    $ cat input.txt | sed 's/unix/Linux/' - > output.txt 
    
  1. -n 与 -p 一起使用: 表示只打印匹配或处理过的行.

    #打印指定的第2行, 以下命令等效
    $ sed -n '2p' input.txt  
    $ head -2 input.txt | tail -1
    #单个文件 NR 与 FNR 相同,
    $ awk 'NR==2' input.txt 
    $ awk 'FNR==2' input.txt 
    
  1. 存在多个输入文件时, sed 默认将他们视为单一持续的流(strem)来处理, 如加入-s参数,则会按不同文件处理

    #准备3个文件
    $ echo 'one' > one.txt
    $ echo 'two' > two.txt
    $ echo 'three' > three.txt
    
    #打印第1行 和最后一行, 三个文件整合成了一个流
    $ sed -n '1p; $p' one.txt two.txt three.txt 
    one
    three
    
    #加入-s后, 三个文件被分别处理
    $ sed -ns '1p; $p' one.txt two.txt three.txt 
    one
    one
    two
    two
    three
    three
    
  2. -e, ; 连接多个scripts

$ sed -e '3d' -e 's#unix#linux#g' input.txt > output.txt #删除第3行后,再进行替换
$ sed '3d; s#unix#linux#g' input.txt > output.txt  # 不用-e, 则需要; 分割

  1. -i[SUFFIX ]直接修改原输入文件

    $ sed -i.bak 's#unix#linux#g' input.txt #i选项后加入.bak后缀,实现自动对原文件备份 文件名为 input.txt.bak
    $ cat input.txt #原文件已经被修改
    linux is great os. linux is opensource. linux is free os.
    learn operating system.
    linux linux which one you choose.
    linux is easy to learn.linux is a multiuser os.Learn linux .linux is a powerful.
    
    
    #注意:  -i 选项 与 -n 选项 不要一起使用 否则如果没有备份, 可能会造成原文件数据丢失
    #原因是 -i 是将打印内容写入原文件, -n则是取消打印  一起使用导致 空内容写入原文件
    #虽然加入p可以解决文件丢失问题,但依然不建议i, n 一起使用
    
    #错误使用的例子:
    $ sed -ni.bak 's#unix#linux#g' input.txt
    $ ll input.txt
    -rw-rw-r-- 1 dliu dliu 0 Apr  8 10:43 input.txt #input.txt内容都没了!!!
    $ ll input.txt.bak 
    -rw-rw-r-- 1 dliu dliu 188 Apr  8 10:40 input.txt.bak #好在进行了备份!
    
    #解决方案: 以下命令完全等效, 还用啥i + np, 多次一举,风险还大
    $ sed -ni.bak 's#unix#linux#gp' input.txt
    $ sed -i.bak 's#unix#linux#g' input.txt
    
  1. n 从下一行开始执行命令

    #如果匹配到free,则下一行的you变成I
    $ sed '/free/{n;s#you#I#}' input.txt 
    unix is great os. unix is opensource. unix is free os.
    unix linix which one I choose.
    unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
    
  2. --debug 查看执行过程

    #查看n的执行过程
    
    $ sed --debug '/free/{n;s#you#I#}' input.txt
    SED PROGRAM:
      /free/ {
        n
        s/you/I/
      }
    INPUT:   'input.txt' line 1
    PATTERN: unix is great os. unix is opensource. unix is free os.
    COMMAND: /free/ {
    COMMAND:   n
    unix is great os. unix is opensource. unix is free os.
    PATTERN: unix linix which one you choose.
    COMMAND:   s/you/I/
    MATCHED REGEX REGISTERS
      regex[0] = 21-24 'you'
    PATTERN: unix linix which one I choose.
    COMMAND: }
    END-OF-CYCLE:
    unix linix which one I choose.
    INPUT:   'input.txt' line 3
    PATTERN: unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
    COMMAND: /free/ {
    COMMAND: }
    END-OF-CYCLE:
    unix is easy to learn.unix is a multiuser os.Learn unix .unix is a powerful.
    
  1. ! 跳过所选行

    #执行s#unix#linux#g时, input.txt第三行修改后变成 linux linix which one you choose. 语义不对, 怎么解决 ?
    #方案: 跳过第三行,其余行进行修改,用到!命令
    $ sed '3!s#unix#linux#g' input.txt
    linux is great os. linux is opensource. linux is free os.
    learn operating system.
    unix linux which one you choose.
    linux is easy to learn.linux is a multiuser os.Learn linux .linux is a powerful.
    
  2. 步长 first~step

    $ seq 10 | sed -n  1~2p  #从1开始, 步长为2 => 打印奇数行
    1
    3
    5
    7
    9
    $ seq 10 | sed -n '0~2p' # 打印偶数行
    2
    4
    6
    8
    10
    
  3. addr1, addr2

```bash
seq 5 | sed -n  '1,3p'  #匹配1-3行
1
2
3
$ seq 5 | sed -n  '3,2p' #add1的总会被匹配
3
```
  1. 0, addr2

    $ seq 10|sed -n '0, /[0-9]/p'  #0, addr2: 一开始第一行就命中了addr2的正则, 其余行就不会命中匹配, 只输入1行
    1
    
    $ seq 10|sed -n '1, /[0-9]/p' #addr1, addr2: addr2的规则不影响起始行addr1, 输出第一行后按addr2规则匹配结束行, 为第二行 于是输出1-2行
    1
    2
    
  1. addr1, ~N

    $ seq  20 | sed -n '10,~8p' #从第10行开始逐行匹配, 直到行数为8的倍数(这里为16)
    10
    11
    12
    13
    14
    15
    16
    
  1. q 终止处理输入行/结束sed

    #打印完前2行后 退出sed执行
    $ sed '2q' input.txt
    unix is great os. unix is opensource. unix is free os.
    unix linix which one you choose.
    

参考:
https://man.linuxde.net/sed
http://c.biancheng.net/view/4028.html
https://www.cnblogs.com/ginvip/p/6376049.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 概述 linux sed命令一次只处理一行内容,处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pat...
    young_d807阅读 689评论 0 0
  • 一、简介 sed英文全称是stream editor。由贝尔实验室开发,如今主流Unix/Linux操作系统上都集...
    程序员蜗牛阅读 311评论 0 0
  • 1、sed简介 Linux sed 命令是利用脚本来处理文本文件。 sed 可依照脚本的指令来处理、编辑文本文件。...
    木子一酱阅读 273评论 0 0
  • 基础 1. 学习基础的bash用法,具体地说,阅读bash的man手册(man bash 并通读一遍);很简...
    Leon_Geo阅读 1,147评论 1 19
  • Linux sed命令是利用script来处理文本文件。sed可依照script的指令,来处理、编辑文本文件。Se...
    姜淑均阅读 739评论 1 2