Shell编程:文本处理器(sed)



sed 编辑器

sed 是一种流编辑器(Stream Editor),用于对文本文件进行行级别的处理。与 vim 不同,sed 处理时不直接编辑文件,而是将文件的每一行读取到临时缓冲区中(称为“模式空间”或 pattern space),在该缓冲区中执行编辑命令,最后将处理结果输出到屏幕或指定的文件。

工作过程

sed 的工作流程包括以下三个主要步骤:

  1. 读取sed 从输入流(文件、管道、标准输入)中读取一行内容并存储到临时缓冲区(模式空间)中。
  2. 执行sed 在模式空间中执行指定的命令,对内容进行相应处理。默认情况下,所有 sed 命令都会顺序执行,除非指定了行的地址范围。
  3. 显示:将修改后的内容输出到标准输出或指定的文件。在输出之后,模式空间被清空并重复上述过程,直至所有输入内容处理完毕。

注意:默认情况下,sed 不会修改源文件内容,除非使用 -i 选项直接编辑文件或使用重定向将输出保存到新文件中。

提高 sed 执行效率的方法

在处理大容量文件时,sed 的执行速度可能会变慢。优化方案:

  • 方案一(推荐使用):使用 split 命令将大文件按行数或大小进行拆分,然后对拆分后的文件分别执行 sed 操作。

    示例:

    # 将一个百万行的文件拆分为每个文件10000行的小文件
    split -l 10000 largefile.txt smallfile_
    
    # 按行分割
    # 用行开分割更直观,推荐工作中使用
    split -l -30 test1.txt  se 
    
    # 按大小分割
    split -b 400M test1.txt se 
    
  • 方案二:使用 cat 文件名 | sed 处理命令 的方式处理文件。这种方法适用于中大型文件,但对于非常大的文件效果不佳。

sed 命令格式与选项

格式

sed '/匹配模式/命令 参数' 文件名

基本操作格式

sed -e '操作' 文件1 [文件2]
# 使用 -e 选项指定编辑操作

sed -f 脚本文件 文件1 [文件2]
# 使用 -f 选项从脚本文件读取操作

sed -i -e '操作' 文件 [文件2] 
# 直接编辑文件(慎用)

执行多条命令

方式一:
sed -e '操作1' -e '操作2' 文件

# 例如
sed -n -e '/^r/p'  -e '/^b/p' /etc/passwd 

方式二:
sed -e '操作1;操作2' 文件

常用选项

  • -e--expression=:指定处理输入文件的 sed 命令。只有一个操作命令时可省略,一般在执行多个操作命令使用。
  • -f--file=:使用指定的脚本文件读取 sed 命令。
  • -h--help:显示帮助信息。
  • -i :直接修改目标文件(慎用)。(in-place)
  • -n:禁止默认输出,仅显示 sed 处理后的结果,通常与p命令结合使用。
  • -r :支持扩展正则表达式。(-E也可以,主要在BSD系统。)

常用操作符(也叫命令)

  • s:替换,替换指定字符。
  • d:删除,删除指定的行。
  • a:增加,在当前行之后添加一行。
  • i:插入,在当前行之前插入一行。
  • c:替换,将选定行替换指定的行。
  • y:字符替换,转换前后的字符长度必须相同。
  • p:打印行。如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以 ASCII 码输出。通常与“-n”选项一起使用。
  • =:打印行号。
  • l:打印文本行,显示不可打印的 ASCII 字符(比如结束符$、制表符\t)
  • r:从另一个文件中读取内容并插入到指定行之后。

分隔符 / 格式说明

sed 命令的语法规则中,正则表达式通常用正斜杠 / 来分隔,用于将模式和命令分隔开来。

  1. 语法结构sed 命令的基本格式是 sed 's/pattern/replacement/' 或者类似的形式,如 sed '/pattern/command'。其中,/ 用来分隔正则表达式(模式)和命令部分。例如:

    • /pattern/ 用于定义一个正则表达式的匹配模式。
    • s/pattern/replacement/ 用于替换模式匹配到的内容。
  2. 可以更换分隔符:实际上 / 并不是唯一的,可使用其他字符作为分隔符,只要在整个命令中保持一致。例如,# 可以用作分隔符,适合用于匹配带有斜杠的路径的情况:

    sed '\\#^/usr/local#d' file.txt
    # # 用于替代 / 作为分隔符。
    

地址定界

sed 命令中的地址定界(addressing)用于指定在哪些行上应用给定的操作。地址定界可以是具体的行号、行范围或匹配模式。sed 根据这些地址定界确定在哪些行上执行操作。

地址定界的类型

  1. 行号:指定特定的行。
    • 示例:sed '2d' file.txt 删除第2行。
  2. 行范围:指定一个行的范围(从某一行到另一行)。
    • 示例:sed '2,4d' file.txt 删除从第2行到第4行的所有行。
  3. 匹配模式:基于内容匹配来指定行。
    • 示例:sed '/pattern/d' file.txt 删除包含 “pattern” 的所有行。
  4. 地址和操作的组合:将操作应用于匹配模式和/或特定行号的组合。
    • 示例:sed '1,3s/foo/bar/' file.txt 将第1行到第3行中所有的 “foo” 替换为 “bar”。

sed 的核心功能

sed 具有增(增加)、删(删除)、改(替换)、查(打印)四大核心功能。

打印功能( p , = , l 命令)

sed 命令可以用来查看文件内容,支持重定向输入和管道符的使用。

sed '' /etc/fstab     # 查看文件内容
sed '' < /etc/fstab   # 使用重定向输入查看文件内容
cat /etc/passwd | sed ''  # 使用管道符查看文件内容

示例

  1. 默认打印方式

    sed 默认会输出所有内容,使用 -n 选项可以禁止默认输出,配合 p 选项打印指定的行。

    sed -e 'p' test1.txt  
    # 默认输出加上'p'会打印两行
    
    sed -n 'p' test1.txt  
    # 使用'-n'禁止默认输出,只打印一行
    
    sed -n '2p' test1.txt 
    # 打印第二行
    
  2. 打印行号和内容

    sed -n '=' test1.txt     # 只显示行号
    sed -n '=;p' test1.txt   # 显示行号和每行的内容
    
  3. 寻址打印

  • 方式一:按照行号打印

    sed -n '1p' test1.txt   # 打印第一行
    sed -n '4p' test1.txt   # 打印第四行
    sed -n '$p' test1.txt   # 打印最后一行
    
  • 方式二:打印行号范围区间

    sed -n '1,3p' test1.txt   
    # 打印1-3行
    
    sed -n '5,$p' test1.txt 
    # 打印第五行到最后一行
    
    sed -n '2,+2p' test1.txt
    # 打印第二行和之后的两行,相当于 2,4p
    
    sed -n '3p;5p' test1.txt  
    # 打印第三行和第五行
    
  • 方式三:指定间隔打印

    sed -n -e '2p' -e'$p' test1.txt  
    # 打印第二行和最后一行
    
    sed -n -e '2p' -e'3p' test1.txt  
    # 打印第二行和第三行 
    
  • 方式四:打印奇数行和偶数行

    n 在 p 前面,跳过一行,打印下一行,就是偶数行

    n 在 p 后面,就是打印第一行,然后跳过一行,形成奇数行

    sed -n 'n;p' test1.txt   # 打印偶数行
    sed -n 'p;n' test1.txt   # 打印奇数行
    
  1. 文本模式过滤行内容打印
  • 方式一:对包含字符串的行进行过滤打印

    sed -n '/o/p' test1.txt   
    # 打印包含 'o' 的所有行
    
    sed -n '/th/p' test1.txt  
    # 打印包含 'th' 的所有行
    
  • 方式二:应用基础正则表达式进行打印

    sed -n '/^root/p' /etc/passwd   
    # 打印以 'root' 开头的所有行
    
    sed -n '/bash$/p' /etc/passwd   
    # 打印以 'bash' 结尾的所有行
    
    sed -n '4,/bash$/p' /etc/passwd  
    # 从第四行开始,一直打印到第一个以bash为结尾的所在行
    
  • 方式三:应用扩展正则表达式进行打印

    注意sed -r 支持扩展正则表达式。同时在使用 {n}{n,}{n,m} 时,括号 {}前不需要加反斜杠 \

    sed -r -n '/(99:){2,}/p' /etc/passwd     
    # 打印包含有两个 '99:' 的行
    
    sed -r -n '/^root|bash$/p' /etc/passwd   
    # 打印以 'root' 开头或以 'bash' 结尾的行
    

删除操作( d 命令)

注意:sed -i 时会对文本进行实际操作,建议对目标文件先进行备份,再进行操作。

示例

  1. 通过行号进行删除

    sed 'd' test1.txt          
    # 删除所有行,什么也不打印
    
    sed -n '3d;p' test1.txt    
    # 删除第三行,打印剩余内容
    
    sed -n '5,8d;p' test1.txt  
    # 删除5到8行,打印剩余内容
    
    sed -n '5,$d;p' test1.txt  
    # 删除5到最后一行,打印剩余内容
    
    sed '4,6!d' test1.txt
    # 除了4-6行,其他的全部删除
    # 如果要生效:sed -i -n 
    
  2. 匹配字符串内容删除

    sed '/one/d' test1.txt          
    # 删除包含 'one' 的行
    
    sed '/one/,/six/d' test1.txt    
    # 删除 'one' 到 'six' 之间的行
    
    sed '/one/,/six/!d' test1.txt
    # 反向删除,除了one-six的行,其余的全部删除
    
    sed '/six/!d' test1.txt 
    # 反向删除,除了six的行,其余的全部删除
    
  3. 字符串搭配正则进行删除

    sed '/^$/d' test1.txt
    # 通过^$,来删除空行;
    
  4. 删除空行

    # 方法一:
    grep -v "^$" test1.txt     # 过滤出非空行
    # 方法二:
    cat test1.txt |tr -s "\n"  # 压缩换行符
    # 方法三:
    sed '/^$/d' test1.txt      # 删除空行
    

替换操作( s , c , y 命令)

格式

sed 使用 s 操作符进行替换:

行范围 s/旧字符串/新字符串/替换标记 

示例

sed 's/旧字符串/新字符串/' test1.txt   
# 替换第一处匹配

sed 's/旧字符串/新字符串/g' test1.txt  
# 替换所有匹配

替换标记和替换命令:

  • 替换标记(Flags)

    sed 的替换操作(s 命令)中使用的是替换标记(flags)。这些标记用来指定替换的行为,通常放在 s/old/new/ 之后。

  • 替换命令(Commands)
    用于不同的替换操作,指定替换操作的类型。它们是 sed 的主要操作指令,通常紧跟在分隔符 / 后面。

常用替换标记

  • 数字:新字符串替换第几处匹配。
  • g:新字符串替换所有匹配。(global)
  • p:打印替换后的行。与“-n”一起使用。
  • w 文件:将替换结果写入文件。

常用替换命令

  • s:替换字符串。(substitute)
  • c:整行替换。
  • y:字符替换,替换前后的字符串长度必须相同。

特殊转换符号

  • \l:将紧随其后的字母转换为小写。
    • 例:sed 's/[A-Z]/\l&/g' file.txt 将所有大写字母转换为小写字母。
  • \u:将紧随其后的字母转换为大写。
    • 例:sed 's/[a-z]/\u&/' file.txt 将匹配的第一个小写字母转换为大写字母(仅对每个替换的第一个匹配字符有效)。
  • \L:将紧随其后的所有字母转换为小写。
    • 例:sed 's/[a-z]/\L&/g' file.txt 将所有匹配的字母转换为小写字母。
  • \U:将紧随其后的所有字母转换为大写。
    • 例:sed 's/[a-z]/\U&/g' file.txt 将所有匹配的字母转换为大写字母。

其他操作符号

  • & :在替换操作中匹配的整个模式。因此,它可以用来引用正则表达式匹配到的内容。
  • | :在扩展正则表达式中表示或操作。

示例

  1. 直接替换字符串( s 命令)

    sed -n 's/root/test/2p' /etc/passwd  
    # 指定第二个 "root",替换为 "test"
    
    sed -n 's/root/test/gp' /etc/passwd  
    # 所有的 "root" 都替换为 "test"
    
    sed -n '/^root/ s/^/#/p' /etc/passwd  
    # 以"root"开头的行,替换开头为空的字符为"#"
    

    将文件中“/var/www/”的内容替换为“/etc/”

    sed "s/\/var\/www/\/etc/" httpd.conf
    
  2. 字母字符大小写转换

    sed 可以用于转换字母的大小写:

    将大写字母转换为小写:

    “l&” 是转换小写的特殊符号

    sed 's/[A-Z]/\l&/g' test1.txt  
    # 将所有大写字母转换为小写,
    # "l&" 是转换小写的特殊符号,需加转义符 "\"
    

    将首字母转换为大写:

    “u&” 是转换首字母大写的特殊符号

    sed 's/[a-z]/\u&/' test1.txt  
    # 将首字母替换为大写,
    # "u&" 是转换首字母大写的特殊符号,需加转义符 "\"
    

    将所有小写字母转换为大写:

    末尾加上 “g”

    sed 's/[a-z]/\\U&/g' test1.txt  
    # 末尾加上 "g",表示全部转换成大写
    
  3. 字符串和字符位置交换

    通过正则表达式的分组和引用,sed 可以轻松实现字符串或字符位置的交换。

    echo ky29ztt | sed -r 's/(ky29)(ztt)/\2\1/'  
    # 输出:zttky29
    
    echo ky27yhtdxl | sed -r 's/(ky27)(yht)(dxl)/\3\2\1/'
    # 输出:dxlyhtky27
    
    echo ky27yhtdxl | sed -r 's/(ky27)(yht)(dxl)/\3\2/'
    # 输出:dxlyht
    
    echo 123abc | sed -r 's/(.)(.)(.)(.)(.)(.)/\6\5\4\3\2\1/'  
    # 输出:cba321
    
    echo 小明明真的帅 | sed -r 's/(.)(.)(.)(.)(.)(.)/\6\5\4\3\2\1/'  
    # 输出:帅的真明明小
    
  4. 整行替换( c 命令)

    使用 c 命令可以替换整行的内容。

    sed '/ONE/c 22' test1.txt  
    # 将包含 "ONE" 的行替换为 "22"
    
    sed '/TWO/c TEST' test1.txt  
    # 将包含 "TWO" 的行替换为 "TEST"
    
  5. 单字符替换( y 命令)

    使用 y 命令对单个字符进行替换,每个字符需要一一对应,不是整体替换。只要有匹配的单字符会全部替换。

    注意:前后字符串长度需要一致,否则会报错。

    sed 'y/TH/12/' test1.txt  
    # 将 "T" 替换为 "1","H" 替换为 "2"
    

增加功能( a , i , r 命令)

sed 支持在指定行后或前增加内容,或从文件中读取内容插入。

常用增加命令

  • a:在下一行添加内容,在指定的匹配行之后插入内容。(append)
  • i:在上一行插入内容,在指定的匹配行之前插入内容。(insert)
  • r:在行后读入文件内容,从文件中读取内容并插入到指定的匹配行之后。(read)

示例:

###用法一:
sed '/three/a 123' test1.txt  
# 在包含 "three" 的行后插入 "123"

sed '/three/i 123' test1.txt  
# 在包含 "three" 的行前插入 "123"

sed '/three/r test.sh' 123.txt  
# 在包含 "three" 的行后插入 "test.sh" 文件内容

###用法二:使用$符号匹配
sed '$r test2.txt' test1.txt  
# 在 test1.txt 最后一行后插入 test2.txt 文件的内容
# $-匹配最后一行,r-读取再插入

sed '$a 123' 123.txt  
# 在 `123.txt` 最后一行插入 "123",a-下一行

sed '$i 123' 123.txt  
# 在 `123.txt` 倒数第二行后插入 "123",i-上一行

sed 's/$/ EOF/' 123.txt
# 使用替换,在每一行末尾添加 "EOF"

使用 -f 指定命令文件(读取规则)

sed 可以通过 -f 参数指定命令文件来处理另一个文件。

示例1

读取 123.txt 的替换规则应用到 456.txt

cat 123.txt
/IPADDR=192.168.233.21/c IPADDR=10.10.10.10

cat 456.txt
IPADDR=192.168.233.21

sed -f 123.txt 456.txt  
# 使用 123.txt 的命令处理 456.txt
# 结果将 IP 地址替换为 "10.10.10.10"

示例2

使用 -f 选项从文件 test27.txt 中读取替换规则,并将这些规则应用到 test27sed.txt 文件的内容上。

cat test27.txt 
s/ /_/g

cat test27sed.txt 
hello world
aaa bbb

sed -f test27.txt test27sed.txt
hello_world
aaa_bbb
# s/ /_/g:用下划线(_)替换所有的空格( )。
# / /:匹配空格
# g:全局替换


  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值