欢迎光临,赤鹿小组
记录过程,分享经验

文本三剑客之 sed 流艺术

Sed 是一个流编辑器。流编辑器用于对输入执行基本的文本转换流。简单点:sed 是用于过滤和转换文本的流编辑器。

格式

sed [option] commond file
  • option:参数选项。
  • commond:需要对文件内每行内容所要的处理。
  • file:处理的文件对象(输入流)。

sed 工作原理

sed 会将读取到的输入流存储到一个叫 “模式空间” 的缓冲区。然后 sed 会在缓冲区内进行循环处理,处理完成后,最后再将缓冲区里处理完成的内容进行输出。

详细步骤:

注意: 在整个处理的过程中,并不会对输入流本身做任何更改。

  • sed 读取输入流的一行,并删除该行的尾随换行符,然后将其放置 “模式空间” 中处理。
  • 执行 sed 命令处理时,会将命令文件中的地址与 “模式空间” 的字符进行匹配,然后在 “模式空间” 中与该地址匹配的部分执行关联的命令,从而更改 “模式空间” 的内容。
  • 当达到匹配行的末尾时,会将删除的尾随换行符重新加回。接着处理下一行,与此往复,知道输入流的末尾。

参考资料

Sed 范围划分

在参阅了 sed, a stream editor 认为 sed 大致可以划分为两类:范围处理动作处理

在开始阐述前,觉得应该介绍一些较为常用的动作:

  • a:在指定行后进行追加文本
  • c:用文本替换更改行
  • d:删除指定行的文本内容
  • p:打印指定行内容
  • r:读取指定的内容
  • w:写入指定文件内容

此外,还需要掌握一个比较中重要命令:s 命令。

sed 's/regexp/replacement/flags' file

范围处理

可以通过指定以英文逗号(,)分隔的来指定地址的范围,一个地址范围从第一个地址匹配处开始的行,一直持续至第二个地址匹配处(包含)。

# -n: 只输出匹配的内容; '2,$p': 打印第2行至末尾的内容; file: 输入流
seq 10 | sed -n '2,$p' 

如果第二个地址是正则表达式,那么检查结束匹配后,将从第一个地址匹配行后面的行开始,而范围将至少跨越 2 行。

seq 10 | sed -n '2,/[0-9]/p'

注意: 如果第二个地址是小于(等于)第一个地址的匹配的行,那么仅只会匹配第一个地址

seq 10 | sed -n '2,1p'

特殊双地址的表达形式

0,/regexp/

注意: 这是 0 地址唯一有意义的地方; 没有第0行,以任何其他方式给出 0 地址的命令都会出错。

在类似于 0,/regexp/ 的地址规范中可以使用 0 行号,这样 sed 也可以尝试在第一个输入行中匹配 regexp。换句话说,0,/regexp/ 类似于 1,/regexp/,除了如果 addr2 匹配输入的第一行,/regexp/form 将认为它结束了范围,而 1,/regexp/form 将匹配其范围的开始,因此使范围跨度达到正则表达式的第二次出现。

seq 10 | sed -n '0,/[0-9]/p'
addr1,+N

匹配 addr1和 addr1之后的 n 行

seq 10 | sed -n '2,+2p'
addr1,~N

匹配 addr1 和 addr1 后面的行,直到输入行号为 n 的倍数的下一行。下面的命令打印从第 2 行开始,直到下一行是 4 的倍数(即第 4 行) :

seq 10 | sed -n '2,~4p'

动作处理

替换匹配的所有:

seq 15 | sed 's/2/4/'

如果需要执行替换的指定的行,那么可以使用地址进行指定:

# 只会替换第 2 行至 15 行中符合的行,而不会替换第 22 行的
seq 25 | sed '2,15s/2/4/'

地址除了可以根据内容的行号进行匹配,还可以包含正则表达式:

# 将 包含 2 的行中的 1 替换成 4
seq 20 | sed '/2/s/1/4/'

# 加上 ! 则是否定了匹配的意义,只选择与地址不匹配的行
seq 20 | sed '/2/!s/1/4/'

使用文件匹配

在 sed 中有一个选项参数是可以使用文件进行匹配的: -f

假设有一个 IP 列表文件

[[email protected] ~]# cat sc.txt
10.0.0.1
10.0.0.2
10.0.0.3

编写 sed 指定的替换文件

cat > sc.sed << EOF
s,10.0.0.1,10.0.0.4,g
s,10.0.0.2,10.0.0.5,g
s,10.0.0.3,10.0.0.6,g
EOF

开始替换

sed -i -f sc.sed sc.txt

插入文件内容

在前面 “范围划分” 的时候,就已经介绍了几个常用的动作,接下来详细介绍下 r 带来的体验

将 sc.sed 的内容插入至 sc.txt 匹配 10.0.0.4 的行的后面:

# 注意对文件所在位置的理解:在单引号内的是添加内容的文件,而在引号外面的是被添加内容的文件。
sed '/10.0.0.4/r sc.sed' sc.txt

控制文件内容写入指定的文件内

将 sc.sed 中的 5跟6 ip 写入至 sc.txt 文件内

sed '/10.0.0.[5-6]/w new.txt' sc.txt

特殊的动作处理

& 符号

& 可以实现在匹配的部分后面添加内容。

# 在所有以 1 开头的部分后面添加 xxx
seq 25 | sed 's/^1.*/&xxx/'

() 括号

在 sed 中,() 也被称为 “预存储技术”,也就是括号内的内容会被一次暂存起来,存储到 \N 里,在使用时则可以使用 /N 的形式来调用 (\1、\2 ……)

# 将匹配的1.*暂存起来,然后在匹配的部分后添加 '10010' 内容
seq 20 | sed 's/\(1.*\)/\110010/'

这里将三个内容进行了预存储:ascmcs (第一个).* (中间的内容)ascmcs (最后一个)

# \1: 在第一个 ascmcs 后添加 10086
# \2: 输出匹配的中间所有内容
# \3: 在最后一个 ascmcs 后添加 10086

echo ascmcs ascmcs ascmcs ascmcs ascmcs | sed 's/\(ascmcs\)\(.*\)\(ascmcs\)/\110086\2\310086/'

更多

请参考:

赞(0)

评论 1

*

code

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #1

    有帮助

    赤鹿小组 2个月前 (08-07) 这家伙可能用了美佬的代理 谷歌浏览器 Windows 10 回复