Shell手册-sed

资料来源

sed修炼系列 | 骏马金龙
sed命令 | runoob

基础知识

Linux sed 命令是利用脚本来处理文本文件。
sed 可依照脚本的指令来处理、编辑文本文件。
Sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。
sed [-hnV][-e<script>][-f<script文件>][文本文件]

循环过程:

  • 读取输入流的一行到模式空间。
  • 对模式空间中的内容进行匹配和处理。
  • 自动输出模式空间内容。
  • 清空模式空间内容。
  • 读取输入流的下一行到模式空间。
(简单来说,把-e指令后面的要求条件文字匹配到后,弄一个临时处理环境。在这个临时环境进行-hnvia的指令处理,然后输出结果,再进行清空临时环境内容后退出环境。接着回到第一步再去匹配文字的循环。)

指令

(一定得看)sed修炼系列(一):花拳绣腿之入门篇

  • -n:禁止默认输出,只输出经过处理的行。
  • -i:直接修改文件内容,如果不指定备份文件,则直接修改原文件,否则将原文件备份并修改。
  • -e:允许同时执行多个命令。
  • -f:指定包含命令集合的SCRIPT文件,让sed根据SCRIPT文件中的命令集处理输入流。
  • -r:使用扩展正则表达式。
    常用命令:
  • p:打印匹配的行。
  • d:删除匹配的行。
  • s:替换匹配的文本。
  • a:在匹配行后面添加文本。
  • i:在匹配行前面插入文本。
  • q:退出 sed 命令。
  • y:替换字符
  • n:手动添加下一行到模式空间
  • =:输出行号
    常用正则表达式:
  • .:匹配任意单个字符。
  • *:匹配前面的字符零次或多次。
  • +:匹配前面的字符一次或多次。
  • ?:匹配前面的字符零次或一次。
  • []:匹配字符集中的任意一个字符。
  • ^:匹配行首。
  • $:匹配行尾。
    定址表达式
  • N:指定一个行号,sed将只匹配该行。(需要注意,除非使用了"-s"或"-i"选项,sed将对所有输入文件的行连续计数。)
  • FIRST~STEP:从第FIRST行开始,每隔STEP行就再取一次。也就是取行号满足FIRST+(N*STEP) (其中N>=0)的行。因此,要选择所有奇数行,使用"1~2";要从第2行开始每隔3行取一次,使用"2~3";要从第10行开始每隔5行取一次,使用"10~5";而"50~0"则表示只取第50行。
  • $:默认该符号匹配的是最后一个文件的最后一行,如果指定了"-i"或"-s",则匹配的是每个文件的最后一行。
  • /REGEXP/:将选择能被正则表达式REGEXP匹配的所有行。如果REGEXP中自身包含了字符"/",则必须使用反斜线转义,即"\/"。
  • /REGEXP/I:和"/REGEXP/"是一样的,只不过匹配的时候不区分大小写。
  • \%REGEXP%:('%'可以使用其他任意单个字符替换。) 这和上一个定址表达式的作用是一样的,只不过是使用符号"%"替换了符号"/"。当REGEXP中包含"/"符号时,使用该定址表达式就无需对"/"使用反斜线""转义。但如果此时REGEXP中包含了"%"符号时,该符号需要使用"\"转义。
  • ADDR1,+N:匹配ADDR1和其后的N行。
  • ADDR1,~N:匹配ADDR1和其后的行直到出现N的倍数行。倍数可为随意整数倍,只要N的倍数是最接近且大于ADDR1的即可。 如ADDR1=1,N=3匹配1-3行,ADDR1=5,N=4匹配5-8行。而"1,+3"匹配的是第一行和其后的3行即1-4行。

例子

#举个例子,假设 `a.sh` 文件的内容如下:
sed 's/\bint\b/SIGINT/g' a.sh

#!/bin/bash
echo "int main() {
    int a = 5;
    return 0;
}"

#使用 `sed 's/\bint\b/SIGINT/g' a.sh` 命令进行替换,结果如下:
#!/bin/bash
echo "SIGINT main() {
    SIGINT a = 5;
    return 0;
}"
  • s 命令表示进行替换操作。
  • / 是默认的定界符,用来分隔正则表达式和替换字符串。
  • \b 表示单词边界,匹配单词的开始或结束位置。
  • int 是要匹配的字符串,这里使用了单词边界 \b 来确保匹配的是单独的 int 单词。
  • / 是第二个定界符,用来分隔匹配字符串和替换字符串。
  • SIGINT 是要替换成的字符串。
  • g 表示全局匹配,即替换所有符合条件的字符串,而不仅仅是第一个。

滑动窗口

  1. 在模式空间中维持窗口大小。这分为两个过程:
    (1)填充窗口到指定行数;
    (2)滑动窗口。

  2. 借助保持空间暂存窗口。
    (1).不断填充保持空间的窗口;
    (2).在填充到指定大小后,将窗口拉回模式空间进行滑动;
    (3).滑动后将其覆盖回保持空间暂存下来。
    (4).继续读取并填充保持空间中的窗口,然后拉回模式空间,滑动后再暂存。

看上去,第一种情况比较容易些。确实如此,第一种情况不用多次考虑两个buffer之间的数据交换。并且,第一种情况的效率更高,因为在达到窗口大小之后,再也无需和保持空间交换数据。

(简单来说,把模式空间看作windows的文件管理器,在里面添加文件夹(文件里的文本),添加到指定数量的文件夹。通过鼠标(多行文本的N、D、P指令)滑动滚动条选择文件夹进行删除/添加/替换)

例子
  1. 假设有一个文件 file.txt,内容如下:
1
2
3
4
5

如果使用 sed 'N;s/\n/ /' file.txt 命令进行处理,结果如下:

1 2
3 4
5

N 命令将每两行作为一个整体进行处理,将每组两行中间的换行符替换为一个空格。

  1. 使用 echo -e "1\n2\n3\n3\n4\n4\n4\n4\n4\n5" | sed -r '$!N;/^(.*)\n\1$/!P;D' 命令进行处理,结果如下:
1
2
3
3
4
4
4
4
4
5
1
2
3
4
5

可以看到,重复的行被过滤掉了。

  • -r 表示使用扩展正则表达式。
  • $!N 表示在除了最后一行之外的每一行后面添加下一行内容。
  • /^(.*)\n\1$/!P 表示如果模式空间中不是两个重复的行,就打印模式空间中的内容。
    • ^ 表示行首。
    • (.*) 表示匹配任意字符,出现 0 次或多次,用括号括起来表示捕获。
    • \n 表示换行符。
    • \1 表示反向引用第一个捕获的分组,也就是前面的 (.*),表示与第一个分组匹配的内容。
    • $ 表示行尾。
      因此,整个正则表达式 /^(.*)\n\1$/ 表示匹配两个重复的行,即两行内容相同且中间有一个空行。
  • D 表示删除模式空间中的第一行并将剩余内容留在模式空间中进行下一轮处理。
posted @ 2023-06-01 14:59  Mugetsukun  阅读(36)  评论(0编辑  收藏  举报