Linux shell文本三剑客之sed的使用

一、sed 概述

  1. sed 是一个流编辑器,用于在输入流(文件或管道中的输入)上执行基本文本转换。
  2. sed 能够对文本文件进行增删改查等操作。
  3. sed 拥有两个缓冲区,活跃模式空间(active pattern space)与辅助保持空间(auxiliary hold space), 简称为活跃区和暂存区,且这两个缓冲区默认都为空。
  4. sed 的基本操作只需要用到活跃区,sed的高级操作需要活跃区与暂存区的相互配合。
  5. 在 sed 的基本操作中,sed 从输入流中得到当前处理的行,会先删除结尾的换行符,存储在一个临时缓冲区,即活跃区;然后 sed 会在活跃区中处理文本,处理完成后加上换行符,并且传送到 stdout (如果没有-n选项),再接着处理下一行,如此循环往复,直至文件末尾,这就是 sed 的基本工作原理。由此可见,sed 在默认情况下是不修改原文件的。
  6. 除非使用特殊命令 (如 “D”), 否则活跃区的数据将在两个周期之间被删除。
  7. 在 sed 的高级操作中,多了一个暂存区,暂存区是与活跃区进行交互的,且以活跃区为主,暂存区为辅,sed 匹配的内容最终都得经由活跃区传输至 stdout 。
  8. sed 的完整语法是

    sed OPTIONS… [SCRIPT] [INPUTFILE…]

二、sed 命令行参数

# 测试数据
# 生成1到100
seq 1 100 > nums.txt
cat>words.txt<<-EOF
hello world
Common methods to solve matrix related problem include DFS, BFS, dynamic programming, etc.
hello123 world123
-hello-
_hello_
EOF
# 生成ASCII表中A到z,包含A-Za-z
printf "%s\n" {A..z} > chars.txt

cat>command.txt<<-EOF
pwd
echo "hello world"
EOF

  1. -n 静默模式,禁止自动打印到标准输出
  2. -e script 可以多次使用-e,将命令加入命令集。在活跃区,命令集会运行处理输入
    sed -n -e '1,3p' -e '2,4p' nums.txt
    
  3. -f script-file 将命令写入文件,使用-f,加入命令集
  4. -i[SUFFIX] 原地编辑文件
    • GUN sed会输出内容发送到临时文件,而不是发送到标准输出,当处理完输入文件后,临时文件会重命名为输入文件的名字
    • 如果提供SUFFIX,那就会在重命名前,将输入文件重命名作为备份。
    • -i后不能有其他短选项,因为如果有会被当做SUFFIX
      # 这样会出现问题,生成nums.txtn的备份文件,而-n也没有生效
      sed -in '1,3p' nums.txt
      # 可以改成这样
      sed -ni '1,3p' nums.txt
      # 或
      sed -n -i '1,3p' nums.txt
      # 或 将名字备份为nums.txt.bak
      sed -n -i.bak '1,3p' nums.txt
      
  5. -E -r 使用拓展正则
  6. -z 和grep -Z类似,常用来处理文件名带空格的文件

三、 sed 脚本

sed 脚本命令的语法为

[addr]X[options]

X是sed单字符的命令;addr是可选的行地址,如果指定,则在匹配的行执行命令X;options是一些sed命令需要的参数。

  1. addr (没有addr就默认是所有行)
    • $ 最后一行
      sed -n '$p' nums.txt
      
    • first~step 首行与步进,例如 1~2 就是奇数行, 2~2就是偶数行, 3~3就是3,6,9…
      sed -n '1~2p' nums.txt
      
    • addr1, addr2 addr1addr2可以是正则表达式和数字。如果addr2是正则,那么检查结束行是从addr1匹配的行后开始,范围至少两行(输入流结束除外)
      sed -n '1,3p' nums.txt
      sed -n '2,/1/p' nums.txt
      # 至少两行
      sed -n '2,/[0-9]/p' nums.txt
      
    • /regexp/ 所有匹配正则的行
      sed -n '/1/p' nums.txt
      
    • 0,/regexp/ 没有第0行,地址0只是为了处理在addr2与输入第1行匹配的情况,其他与1,/regexp/相同
      sed -n '0,/1/p' nums.txt
      sed -n '1,/1/p' nums.txt
      
    • addr1,+N 匹配addr1,然后N
      sed -n '1,+5p' nums.txt
      # 所有匹配1的行加上后5行
      sed -n '/1/,+5p' nums.txt
      
    • addr1,~N 匹配addr1,然后到N的倍数行
      sed -n '/1/,~4p' nums.txt
      
    • ! 在上面的地址后加一个!,表示相反匹配
      sed -n '/1/,~4!p' nums.txt
      
  2. X
    • a text 在行下方添加文本
      sed '1a hello\nworld' nums.txt 
      
    • b label 无条件调到label
    • c text 替换行文本
      sed '1c hello\nworld' nums.txt 
      
    • d 删除活跃区内容,立即开始下个循环
      sed '1,3d' nums.txt 
      
    • D 如果活跃区包含换行符,则删除第一行,包含换行符。如果不包含换行符,则和d一样
      sed 'N;$!D' nums.txt
      
    • e 执行在活跃区的shell命令
      sed 'e' command.txt 
      
    • e command 执行command
      # 使用e pwd可以在每行前输出前执行命令
      sed 'e pwd' command.txt
      
    • F 打印当前输入文件的名字
      sed 'F' nums.txt command.txt 
      
    • g 将活跃区内容替换为缓存区内容
    • G 将活跃区内容加上换行符,然后将暂存区内容追加到活跃区
    • h 将暂存区内容替换为活跃区内容
    • H 将暂存区内容加上换行符,然后将活跃区内容追加到暂存区
    • i text 在行的上方添加文本
      sed '1,3i hello\nworld' nums.txt 
      
    • n 跳过行
      # 两个n跳过2行,每3行执行p
      sed -n 'n;n;p;' nums.txt
      
    • N 向活跃区添加换行符,接着再把下一行加进去。
      sed 'e echo ---' nums.txt
      sed 'N;e echo ---' nums.txt
      sed 'N;N;e echo ---' nums.txt
      
    • p 打印活跃区内容
      sed -n '1,10p' nums.txt 
      
    • P 打印活跃区的第一行
      # 每两行打印第一行
      sed -n 'N;P' nums.txt
      
    • q[exit-code] 退出sed
      # 到第2行退出sed
      sed '2q10' nums.txt
      echo $?
      
    • r filename 读文件
      # 每行都会读command.txt,并默认打印出来
      sed 'r command.txt' nums.txt
      
    • s/regexp/replacement/[flags] 替换字符
      • g 全局替换
      • numbernumber次匹配才替换
      • p 如果进行了替换,则打印活跃区内容
      • w filename 如果进行了替换,则将结果写入filename
      sed 's/1/a/' nums.txt
      sed 's/1/a/2' nums.txt
      sed -n 's/1/a/p' nums.txt
      sed -n 's/1/a/2p' nums.txt
      
    • w filename 将活跃区内容写入文件
      sed -n 'w file.txt' nums.txt
      
    • x 交换活跃区与暂存区内容
    • y/src/dst/ 将活跃区的内容,按照匹配src的字符转化dst相同位置的字符
      sed 'y/123/abc/' nums.txt
      
    • z 清空活跃区内容
    • # 注释,直到下一行
    • { cmd ; cmd … } 命令组
      sed -n '1p;2p;100p' nums.txt
      sed -n '1{s/1/a/;p}' nums.txt
      
    • = 打印当前输入行数
      sed -n '=' nums.txt
      
    • : label 给分支命令(b, t, T)指定label位置
      # 定义标签t;使用N输入两行;将\n替换为,;使用b跳到标签t循环
      # 将所有换行替换为,
      sed ':t;N;s/\n/,/;b t'
      

参考链接:

  1. http://blog.51cto.com/liansir/1836673
  2. http://www.gnu.org/software/sed/manual/sed.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章