我正在尝试将文本添加到行的前 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 test
,perl
也将是最佳选择:
perl -pi -e 's{This is a test\K}{$n++ < 3 ? "." : ""}ge' your-file
^不使用-i inplace
as尝试首先从当前工作目录gawk
加载inplace
扩展(asinplace
或),有人可能已经在其中植入了恶意软件。随系统提供的扩展inplace.awk
的路径可能会有所不同,请参阅输出inplace
gawk
gawk '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