匹配后替换第N行

匹配后替换第N行

假设我有一个包含五百行文本的文件。

one
two
three
four
five
six
seven
eight
nine
ten
.
.
.
five-hundred

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

sed '/two/{n;n;n;n;n;s/.*/MODIFIED/}' inputfile

输出:

one
two
three
four
five
six
MODIFIED
eight
nine
ten
.
.
.
five-hundred

但是如果我想在比赛结束后替换第 60 行怎么办?我不想写六十次“n”。

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

答案1

解决方法awk

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

或者如果你想更换线路

awk '/two/{ n=NR+5 } NR==n{ $0="MODIFIED" }1' file

答案2

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

awk -v offset=60 '
    /two/ {x[NR + offset]}
  NR in x {delete x[NR]; $0 = "MODIFIED"}
          {print}'

每当上面的第 60 行包含 时,将确保替换一行two

答案3

/two/{
    :loop
    N
    /\(\(.*\n\)\{5\}\).*/{
        s//\1Modified/
        b
    }
    b loop
}

将其保存x.sed并执行为

sed -f x.sed file

或者使用 GNU Sed 的单行代码:

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

逐行分析:

  • 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

首先是递减计数器c,并且因为所有变量c最初都是零,所以只有在找到匹配项时才会变为正数。

更明确的方法是

awk 'BEGIN{c=-1};/two/{c=5};c==0{$0="Modified"};{print};c>=0{c=c-1}' file

有用的 Sed 资源:

答案4

进行全行字符串匹配,并假设这样的匹配不会在 5 行范围内重复出现,在每个 Unix 机器上的任何 shell 中使用任何 awk:

$ awk 'c&&!--c{$0="MODIFIED"} $0=="two"{c=5} 1' file
one
two
three
four
five
six
MODIFIED
eight
nine
ten
.
.
.
five-hundred

https://stackoverflow.com/questions/17908555/printing-with-sed-or-awk-a-line-following-a-matching-pattern/17914105#17914105

相关内容