如何使用 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 我希望能有一个 简单且愚蠢的 解决方案。不是 awk 或 sed 中的标签和循环的解决方案。
第一个解决方案: 恕我直言,如果你问我简单的解决方案,那么我会选择 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 种解决方案: 更通用的解决方案,人们可以给出字段编号的范围,从哪个字段到哪个字段将值设置为 ****
然后尝试以下(from
和 to
是可以由人设置的变量,以根据字段编号更改值)。
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
我一直在寻找一种简单的方法来使用 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 我希望能有一个 简单且愚蠢的 解决方案。不是 awk 或 sed 中的标签和循环的解决方案。
第一个解决方案: 恕我直言,如果你问我简单的解决方案,那么我会选择 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 种解决方案: 更通用的解决方案,人们可以给出字段编号的范围,从哪个字段到哪个字段将值设置为 ****
然后尝试以下(from
和 to
是可以由人设置的变量,以根据字段编号更改值)。
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