sed 在第 n 次出现后替换任何内容

sed replace anything after nth occurence

我是 Bash 脚本编写的新手,一直在寻找关于如何在第 n 次出现后使用 sed 替换任何内容(而不是替换第 n 次出现)的正确答案。

例如,如果我想更改第 2 个 space 之后的任何内容,我会将以下句子作为输入:Today is a good day,并将以下句子作为结果:Today is a friday

有什么想法吗?

我会说

 echo 'Today is a good day.' | sed 's/ /&\n/3; s/\n.*/friday/'

这包含两个命令:

s/ /&\n/3       # inserts a \n after the third space
s/\n.*/friday/  # replaces \n and everything that comes after it with "friday"

这利用了 \n 永远不会出现在一行中的事实——这使得 \n 在 sed 脚本中作为标记非常有用。 & 指的是该行的匹配部分。

您可以使用:

s='Today is a good day'
echo "$s" | sed 's/^\(\([^[:space:]]\+[[:space:]]\+\)\{3\}\)[^[:space:]]\+[[:space:]]\+/fri/'
Today is a friday

使用-r简化:

cho "$s" | sed -r 's/^((\S+\s+){3})\S+\s+/fri/'
Today is a friday

为什么不直接使用 awk

echo "Today is a good day" | awk '{print ,,"a friday"}'
Today is a friday

这将保留前两个字段,并替换该行的其余部分。

据我了解所问的问题,如果您使用的是 Unix 第 7 版 shell 或基于它的较新的 shell,例如 sh,这实际上甚至不需要 sed 或 awk或 bash。只需使用 set 命令的一个不幸的晦涩功能:

$ set Today is a good day
$ echo   "Friday"
Today is Friday

最初的问题询问的是模式,但提供的示例中的模式只是一个 space。 space 的第二次出现隐式地跟在第二个参数之后。我想,您可以使用一些 shell 算法使其适应 "nth occurrence"。

虽然我最近才发现这个技巧,但它已经存在很长时间了。它的使用示例出现在 Kernighan 和 Pike 的 "The UNIX Programming Environment" (1984) 的第 136 页。它在 Bash 上的工作原理相同,我猜想它一定出现在任何第 7 版中。 shell导数。