如何使用 sed 替换 bash 中第 n 次到第 n 次出现的字符串?

How to replace mth to nth occurance of a string in bash using sed?

我一直在寻找一种简单的方法来使用 sed 在每行 中屏蔽(即用 * 替换)给定模式的第 1 到第 3 次出现。

输入文本的格式为;

$ cat input
1234 4321 2356 7890
3456 4567 8765 0981
2345 2167 9876 1234

要求的输出;

**** **** **** 7890
**** **** **** 0981
**** **** **** 1234

环顾四周后,我找到了替换 指定模式的第 n 次出现 的方法。此处如何替换给定输入中每一行的第二个块。

$ cat input | sed  's/[0-9]\{4\}/****/2'
1234 **** 2356 7890
3456 **** 8765 0981
2345 **** 9876 1234

我们还可以替换给定模式第n次出现所有出现次。方法如下。

$ cat input | sed  's/[0-9]\{4\}/****/2g'
1234 **** **** ****
3456 **** **** ****
2345 **** **** ****

P.S 我希望能有一个 简单且愚蠢的 解决方案。不是 awksed 中的标签和循环的解决方案。

第一个解决方案: 恕我直言,如果你问我简单的解决方案,那么我会选择 awk。如果您的 Input_file 仅包含 4 个字段,那么只需将值分配给 3 个字段即可。

awk '{==="****"} 1'  Input_file

第二个解决方案:sed(这可能是OP试图写的方式)。使用 sed 的功能来使用临时缓冲区存储匹配的正则表达式,然后在替换时用 **** 替换它。

sed 's/\([^ ]*\) \([^ ]*\) \([^ ]*\) \(.*\)/**** **** **** /'  Input_file

第三个解决方案: 使用rev打印Input_file reverse then catch only first(这实际上是Input_file) 中的最后一个字段,然后打印 3 次 **** 并再次反向打印,这将以实际形式打印它:)

rev Input_file | sed 's/\([^ ]*\).*/ **** **** **** ****/' | rev

第 4 种解决方案: 更通用的解决方案,人们可​​以给出字段编号的范围,从哪个字段到哪个字段将值设置为 **** 然后尝试以下(fromto 是可以由人设置的变量,以根据字段编号更改值)。

awk -v from="1" -v to="3" '{for(i=from;i<=to;i++){$i="****"}} 1' Input_file

"Simple" 和 "stupid" 你问。我会让你来决定这是怎么回事 ;)。 GNU sed 确实支持从 sed /../[n]g 开始替换的模式,但不允许停止范围。您可以提及 2g,从第 2 次出现开始替换,但不能定义范围,如第 1 次到第 3 次出现。

sed -e 's/[0-9]\{4\}/****/; s/[0-9]\{4\}/****/; s/[0-9]\{4\}/****/' file

但是拒绝 awk 像这样的微不足道的替换 不是 一个好主意。它比您想象的更有用和简单易用。

以你的简单输入为例:

sed -r 's/([0-9]{4} ){3}/**** **** **** /' input

https://unix.stackexchange.com/a/155810/57293中给出了更复杂的解决方案。

另一个简单的解决方案(当您知道行中模式的数量时)是

rev input | sed -r 's/[0-9]{4}/****/g2' | rev