Unix 排序不接受非常规分隔符“±”作为字段分隔符

Whi*_*cal 9 shell bash sort unicode

我都试过了

... | sort -k'1,1r' -k'2,2' -t'±'

... | sort -k'1,1r' -k'2,2' -t$'\xC2\xB1'


*$> sort: ±: Invalid argument*
Run Code Online (Sandbox Code Playgroud)

我希望它不是不受排序支持,只是我缺少一些转义或特殊字符处理。

我的设置是:

localhost:~ user$ locale
LANG=
LC_COLLATE="C"
LC_CTYPE="UTF-8"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=

localhost:~ user$ sort --version
2.3-Apple (99)
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 27

如果您查看Apple macOSsort源代码,它的FreeBSD 起源几乎没有修改

特别是,您会发现-t选项的处理方式与 FreeBSD 中相同

            case 't':
                while (strlen(optarg) > 1) {
                    if (optarg[0] != '\\') {
                        errc(2, EINVAL, "%s", optarg);
                    }
                    optarg += 1;
                    if (*optarg == '0') {
                        *optarg = 0;
                        break;
                    }
                }
Run Code Online (Sandbox Code Playgroud)

如您所见,-t只有当参数为空(在这种情况下 NUL 是分隔符)或包含单个字节或以任意数量的\字符开头,后跟单个字节(在这种情况下该字节被视为分隔符),或0后跟任何内容,在这种情况下,分隔符是NUL.

例子:

  • -t ''or -t '\0', or -t '\\\\\0'or-t '\\0whatever分隔 NUL 字符
  • -t '\t',-t '\\\t'划定t
  • -t '\',-t '\\\\\'以反斜杠分隔。

在任何情况下,分隔符只能是一个字节,神秘的额外处理可能只有在那里-t '\0'才能用于指定 NUL 分隔符以与 GNU 兼容sort(FreeBSDsort曾经是 GNU sort),或者可能(因为那个提交是甚至不是关于-t选项),所以它-t '\\'也可以用来指定\为分隔符(不是 GNUsort接受的东西)。

所以你不能使用多字节字符作为分隔符。

没有多少sort实现允许多字节字符。GNU 或busyboxsort也没有。不过 ast-opensort确实如此。

在这里,您可以±在排序之前将其与单字节字符(最好是不太可能出现在输入中的字符,因此它不会影响排序)交换,然后再进行排序和恢复。谢天谢地,FreeBSDtr和 macOStr也支持多字节字符(与 GNU 不同tr):

<input tr '±\1' '\1±' | sort -t $'\1' ... | tr '±\1' '\1±'
Run Code Online (Sandbox Code Playgroud)

  • 令人遗憾的是,即使到了 2020 年,基本的文本处理工具也是建立在从根本上被打破的假设上,而这些假设在 3-5 年(如果有的话)中都不成立。 (9认同)
  • @Whimusical,我不会依赖它。0xC2 是字符 U+0080 到 U+00BF 的第一个字节,而不仅仅是 `±`。这也意味着您的第二个键将以“\xB1”开头,这意味着无效文本。一些 `strcoll()` 实现会因此而窒息。它也有可能打破 macOS 修复其“排序”以支持多字节分隔符的日子。 (4认同)