对于某些问题,例如在未知行数上匹配模式或“替换...的最后一次出现” -z
,GNU的选项sed
非常有用。我怎样才能实现同样的便携?
示例:我有一个文件
yellow, green,
blue, black, purple,
orange,
white, red, brown
are some colours
我想用 . 替换文件的最后一个逗号and
。请注意,逗号在哪一行或该行中的哪个位置是未知的。使用 GNU sed
,我可以做到
sed -z 's/\(.*\),/ \1 and/'
获得所需的输出
yellow, green,
blue, black, purple,
orange,
white, red and brown
are some colours
我怎样才能以可移植的方式做到这一点,这将与任何 POSIX 一起运行sed
?
在纯 POSIX
sed
中,您必须自己粘贴所有行。虽然有些人N
在循环中执行此操作,但最简单的方法是使用以下模式附加到保持空间H;1h;$!d;x
:H
将每一行附加到保持空间。不幸的是,附加第一行会在缓冲区的开头添加一个换行符,所以1h
将覆盖第一行的保留空间以避免错误的换行符。$!d
将结束对除最后一行之外的所有行的处理。它们不需要打印,因为它们存储在容纳空间中x
将仅在最后一行之后执行(对于所有其他行,d
确实停止了进一步的命令处理)并且它将x
更改保持空间和模式空间,因此在此命令之后,收集在保持空间中的整个文件将在模式空间中,就像使用-z
GNU 选项一样sed
。当然你也可以使用g
代替x
,但这会产生大量的复制,所以x
速度更快。因此,该示例的脚本将如下所示:
请注意,处理这样的文件对于非常大的文件不是一个好主意,因为这将使用大量 RAM。
sed 用于对单个字符串执行简单的 s/old/new,仅此而已。几乎任何时候你发现自己使用了除 s、g 和 p(带 -n)之外的结构,当然任何时候你发现自己在谈论“保持空间”时,你都在使用错误的工具。对于比 s/old/new 更复杂的任务,比如这个任务,你应该只使用 awk 来代替。以下将在任何 UNIX 机器上的任何 shell 中使用任何 awk 工作,不会将整个文件存储在内存中,并且如果/当您想对文本另外做任何其他事情时,调整它是微不足道的:
您可以在 awk 中更简单地完成这项工作,方法是将整个文件放入内存并编写这个神秘的符文:
但关键是,与 sed 不同,您不必这样做。