sed:如何将文本添加到前x个出现的位置

sed:如何将文本添加到前x个出现的位置

我正在尝试将文本添加到行的前 x 次出现的末尾。我知道如何在全球范围内以及在第 n 次发生时执行此操作。我不知道如何在前 n 次出现时执行此操作。一个示例是包含以下内容的 text.txt 文件:

This is a test
junk
This is a test
More junk
This is a test
This is a test
This is a test

而且,我想添加一个“.”在前三次结束时出现“这是一个测试”。我想要得到的输出是:

This is a test.
junk
This is a test.
More junk
This is a test.
This is a test
This is a test

答案1

This.*test是正确的正则表达式。星号表示“前一个字符的 0 次或多次”,因此This*test不会与您的任何行匹配。

现在,Sed 不擅长算术。对于优雅的东西,我建议 Awk:

awk '/This.*test/{c++};{print $0 (c<4 ? "." : "")}' file

我认为只要说c,就像 Awk 中任何未设置的变量一样,都被视为零,但如果您需要进一步说明,请告诉我。

答案2

另一种变体可以避免在找到所有 3 个匹配项后进行正则表达式匹配:

awk -v n=3 'n && /This is a test/ {n--; $0 = $0 "."}; {print}'

具体sed而言,您可以执行以下操作:

sed '
  1 {
    x
    s/^/.../
    x
  }
  /This is a test/ {
    s/$/./
    x
    s/.//
    /./ {
      x
      b
    }
    g
    :1
    $! {
      n
      b 1
    }
  }'

我们跟踪要附加的 s 数量,作为保留空间中.相应的 s 数量。.

不用说,这sed对于此类任务来说不太合适。如果想要的原因sed是为了-i在一些实现上找到就地编辑的扩展(借自perl),请注意,GNU 实现awk也可以使用 1 来实现-i /usr/share/awk/inplace.awk,或者您可以使用真实的东西:

perl -lpi -e '
  if ($n < 3 && /This is a test/) {
    $n++;
    $_ .= ".";
  }' your-file

如果您想.在每次出现 后添加 ,This is a test而不是在所有包含至少一次出现 的行之后添加This is a testperl也将是最佳选择:

perl -pi -e 's{This is a test\K}{$n++ < 3 ? "." : ""}ge' your-file

^不使用-i inplaceas尝试首先从当前工作目录gawk加载inplace扩展(asinplace或),有人可能已经在其中植入了恶意软件。随系统提供的扩展inplace.awk的路径可能会有所不同,请参阅输出inplacegawkgawk 'BEGIN{print ENVIRON["AWKPATH"]}'

答案3

我们perl可以如图所示

perl -lpe '
  $_ = $k == 3 ? next : s/This is a test(?{$k++}).*\K/./r;
' file

大象也会跳舞,尽管舞步很简单。使用GNU sed扩展正则表达式模式下的写入,-E 我们可以将计数存储为保留中的换行符数量。

K=3
sed -Ee '
  /This is a test/!b
  G
  /(.*\n){'"$K"'}.*\n/!{
    s/\n+/./p;z;H;d
  }
  s/\n+//
  :a;n;ba
' file

相关内容