删除具有非字符值的字节时tr -c -d的行为

时间:2015-03-25 14:50:33

标签: shell posix tr

我无法理解http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tr.html的“理由”部分中的这一段。

  

ISO POSIX-2:1993标准的-c选项表现相似   到-C选项,但没有提供相当于的功能   POSIX.1-2008中指定的-c选项。这意味着能够指定tr -cd \ 000- \ 177的历史实践(将删除   设置最高位的所有字节都没有效果,因为在C中   语言环境,值为八进制200到八进制377的字节不是   字符。

但是,我对CentOS 6.5系统的测试似乎表明它似乎确实有效。

$ export LC_ALL=C
$ export LANG=C
$ locale
LANG=C
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=C
$ printf "\x41\x42\x81\x82" | od -t x1
0000000 41 42 81 82
0000004
$ printf "\x41\x42\x81\x82" | tr -c -d "\000-\1777" | od -t x1
0000000 41 42
0000002

命令tr -c -d "\000-\1777"确实删除了值为\x81\x82的字节。为什么我的测试结果不符合规范中的内容?

1 个答案:

答案 0 :(得分:3)

由于您使用的是CentOS,因此您的tr命令很可能来自GNU coreutils包。 GNU tr(尚未)区分-c-C的行为。在tr的最新版本中,-c-C都是--complement选项的等效短选项。

根据GNU documentation for tr

  

目前tr完全支持单字节字符。最终它将支持多字节字符;当它这样做时,-C选项将使它补充字符集,而-c将使它补充值集。仅当某些值不是字符时,此区别才有意义,并且仅当输入包含编码错误时,才可能在使用多字节编码的区域设置中进行此区分。

我还发现POSIX规范中引用的段落令人困惑,但我同意Etan Reisner的解释,即“符合1993版规范的实现将被破坏,但早期的实现(历史)和实现符合2008(及更新)规范将起作用。“

在任何情况下,GNU tr都没有(还)实现2008 POSIX规范的这一部分(即区分字符),所以它不能用于测试。

顺便说一下,7命令中有一个冗余的tr -c -d "\000-\1777"