我得到一个文件alphabet
,a
其中一行有多个出现的情况。
$ cat alphabet
a b c d e f g
h i j k a a l
m n a p q r a
s t u v w a x
y z a k l q z
在哪里
$ cat alphabet | grep -o a | wc -l
7
现在我怎样才能替换前 3 次出现的内容,a
以便Z
我的文件如下所示
Z b c d e f g
h i j k Z Z l
m n a p q r a
s t u v w a x
y z a k l q z
答案1
awk '{
for (i=1; i<=NF; i++)
if ($i == "a" && n < 3) {
n++
$i = "Z"
}
print
}' alphabet
或者,“一行”
awk '{for (i=1;i<=NF;i++) if ($i=="a" && n++<3) $i="Z"; print}' alphabet
答案2
Perl 来救援:
perl -pe '$c++ while $c < 3 && s/a/Z/' alphabet
答案3
awk
已发布的解决方案假设所有出现的都是a
单独的单词。虽然这适用于例子数据,但并未指定真实数据是否正确。以下解决方案更符合已发布的解决方案awk
的精神:perl
awk '{ while (changes < 3 && sub("a", "Z") > 0) changes++; print }' alphabet
这将取代(子
当然,要真正改变文件,你需要做类似的a
事情Z
changes
awk '{while (c < 3 && sub("a","Z")>0) c++; print}' alphabet > t && cp t alphabet && rm t
t
临时文件在哪里。
答案4
这里,sed 方式
sed -E ':a;N;$!ba;s#a#Z#;s#a#Z#;s#a#Z#' alphabet
由于 sed 通常按行工作,因此任何 sed 命令每次都只能作用于一行。为了能够只替换前 3 次出现的内容,我们需要首先将整个文件设为一个单一选择,然后对它进行 3 次替换。否则,我们将对每一行进行 3 次替换。
:a
创建标签N
将下一行添加到模式空间$!
跳过最后一个换行符ba
要标记的分支a
现在,我们选择了整个文件,并将对该空间进行操作,而不是一次对一行进行操作,将“a”替换为“Z”。
上述命令只适用于 GNU sed,更通用但有点丑陋的版本应该适用于非 GNU sed:
sed -e ':a' -e 'N' -e '$!ba' -e 's#a#Z#' -e 's#a#Z#' -e 's#a#Z#' alphabet
编辑:如评论中所建议,添加使用 g 命令的版本,首先将所有出现的“a”替换为“Z”,然后将第 3 次之后的所有出现的“Z”再次替换为“a”,这实际上会导致仅替换前 3 次出现的“a”。这样,您可以更改最后一个数字以反映所需的替换次数。
sed -e ':a;N;$!ba;s#a#Z#g;s#Z#a#g4' alphabet