使用 POSIX sed 删除不可打印字符

使用 POSIX sed 删除不可打印字符

roff使用其他“老式”工具(例如许多 Unix 系统上的手册页)创建的文件在简约终端中生成粗体和下划线文本,使用涉及不可打印 ASCII 字符(如“半退格”)的技巧^H来获取粗体和下划线文本,例如:

b^Hbo^Hol^Hld^Hd and _^Hu_^Hn_^Hd_^He_^Hr_^Hl_^Hi_^Hn_^He_^Hd

如果我希望将其转换为人类可读的纯文本bold and underline(忽略格式),我可以vim使用类似:%s:\(.\)\b\1:\1:ge | %s:_\b\(.\):\1:ge.

我还可以通过管道传输文本tr -dc并使用 Perl 的一些正则表达式魔法来查找完全由重复字符对构建的单词。

sed然而,这看起来像是 plain应该能够处理的 事情,这将使在脚本中使用它更加干净。

问题:这个翻译可以吗仅有的使用 POSIX sed,即不使用 GNU 或 BSD 扩展?

这里给我带来麻烦的只是不可打印的字符^H(ASCII #8)。 Bruce Barnett 的书中提到了一个技巧Sed - 简介,但不知何故我无法让它工作。

答案1

你能做这个吗仅有的使用 POSIX sed?是的:

sed -e 's/.^H//g' < data

其中^H只是一个字面退格字符。 POSIXsed使用POSIX 基本正则表达式,它们是通过字节定义的 - 是否打印字符,它们并不关心,因此其行为与^H字母相同。这里不涉及扩展。请注意,您真正想要做的就是删除退格的字符,因此示例中的捕获组并不是真正必要的。

在大多数情况下,您可以使用 键入退格字符Ctrl+V Ctrl+H

我认为你潜在的问题是“我如何在 shell 脚本中做到这一点?”,其中字面的退格字符可能会令人不愉快(尽管vim会很乐意接受同样的Ctrl+V Ctrl+H写法)。这是您链接的介绍的用途tr

POSIXtr支持各种各样的转义字符\b,包括退格字符的符号转义。您可以将退格字符保存到变量中,并将该变量替换为sed上面的表达式:

BACKSPACE=$(echo x | tr 'x' '\b')
sed -e "s/.$BACKSPACE//g" < data

我们只是告诉用退格字符tr替换 an ,并给它一个 single作为输入。这在我可以访问的每个系统上都运行良好,包括 Solaris。然而,xxprintf也是 POSIX 定义的工具,并且它支持相同的转义:

BACKSPACE=$(printf '\b')
sed -e "s/.$BACKSPACE//g" < data

这比tr版本更简单、更直接。请注意表达式周围的双引号sed,以便我们不再抑制变量插值。你也可以使用命令替换printf '\b'如果您只想使用一次,而不是使用变量,则可以使用 inline 直接将其放入。

我们可以检查这是否适用于hexdump(或hd):

$ dash
$ hexdump -C data
00000000  62 08 62 6f 08 6f 6c 08  6c 64 08 64 0a           |b.bo.ol.ld.d.|
$ BACKSPACE=$(printf '\b')
$ sed -e "s/.$BACKSPACE//g" < data | hexdump -C
00000000  62 6f 6c 64 0a                                    |bold.|

根据需要,退格字符和删除的前面字符将从输出中删除(0a是终止换行符)。

相关内容