匹配后替换第 N 行

cji*_*jcb 8 sed awk text-processing

比方说,我有这个包含 500 行文本的文件。

one
two
three
four
five
six
seven
eight
nine
ten
.
.
.
five-hundred
Run Code Online (Sandbox Code Playgroud)

如果我想用某个字符串替换匹配后的第五行,我会这样做:

sed '/two/{n;n;n;n;n;s/.*/MODIFIED/}' inputfile
Run Code Online (Sandbox Code Playgroud)

输出:

one
two
three
four
five
six
MODIFIED
eight
nine
ten
.
.
.
five-hundred
Run Code Online (Sandbox Code Playgroud)

但是如果我想在匹配后替换第 60 行呢?我不想写 'n' 次。

我尝试使用 x、h/H、g/G 和范围,但仍然无法获得所需的输出。

Fre*_*ddy 11

解决方法awk

awk '/two/{ n=NR+5 } NR==n{ sub(/.*/, "MODIFIED") }1' file
Run Code Online (Sandbox Code Playgroud)

或者如果你想更换线路

awk '/two/{ n=NR+5 } NR==n{ $0="MODIFIED" }1' file
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 9

对于此类任务,您可能需要考虑如果在偏移之前再次出现搜索模式该怎么办。

awk -v offset=60 '
    /two/ {x[NR + offset]}
  NR in x {delete x[NR]; $0 = "MODIFIED"}
          {print}'
Run Code Online (Sandbox Code Playgroud)

只要上面的 60 行包含two.


Qua*_*odo 6

/two/{
    :loop
    N
    /\(\(.*\n\)\{5\}\).*/{
        s//\1Modified/
        b
    }
    b loop
}
Run Code Online (Sandbox Code Playgroud)

将其保存x.sed并执行为

sed -f x.sed file
Run Code Online (Sandbox Code Playgroud)

或使用 GNU Sed 的 one-liner:

sed '/two/{:a;N;/\(\(.*\n\)\{5\}\).*/{s//\1Modified/;b;};ba;}' file
Run Code Online (Sandbox Code Playgroud)

逐行分析:

  • 1-2:找到匹配后,开始循环。在这个循环中,
    • 3:使用N命令在模式空间中添加一行。
    • 4:如果有 5 个换行符——基本的正则表达式是\(.*\n\)\{5\}——,把它放在一个捕获组中,不捕获最后一行 ( .*) 并且
      • 5:用捕获组替换整个模式空间*,后面跟着Modified一行。
      • 6:打破循环。
    • 8:loop再一次。

*一个空的正则表达式槽相当于之前使用的正则表达式,所以第 5 行相当于s/\(\(.*\n\)\{5\}\).*/\1Modified/.


不太深奥的是使用 awk:

awk '{c--};/two/{c=5};c==0{$0="Modified"};{print}' file
Run Code Online (Sandbox Code Playgroud)

这从递减一个计数器开始c,因为所有变量c最初都是零,只有在找到匹配项时才会变为正值。

更明确的方法是

awk 'BEGIN{c=-1};/two/{c=5};c==0{$0="Modified"};{print};c>=0{c=c-1}' file
Run Code Online (Sandbox Code Playgroud)

有用的 Sed 资源:


ImH*_*ere 5

一个sed(但只有 GNU sed)没有循环和使用简单范围的解决方案是:

sed '/^two$/,+5{/^two$/,+4{b};s/.*/& hello/}'
Run Code Online (Sandbox Code Playgroud)

唯一需要调整的是匹配正则表达式以及 +5 和 +4 计数器。

比赛结束后的 100 行:

sed '/two/,+100{/two/,+99{b};s/.*/& Modified/}'
Run Code Online (Sandbox Code Playgroud)

也许这可以澄清它是如何工作的:

$ seq 10 | sed '/4/,+3{/4/,+2{s/.*/&changed/;b};s/.*/& Modified.../}'
1
2
3
4changed
5changed
6changed
7 Modified...
8
9
10

Run Code Online (Sandbox Code Playgroud)