根据区域设置对 ls 输出进​​行排序,但不忽略非字母数字字符

根据区域设置对 ls 输出进​​行排序,但不忽略非字母数字字符

假设我有一个包含文件_b, a, c, č,的目录d。我想根据 cs_CZ.UTF8 语言环境对文件进行排序,但是没有忽略下划线,即像这样:_b a c č d

目前,lsls | sort也)像这样对文件进行排序:a _b c č d.我找到的所有答案都建议使用LC_COLLATE=C,但这会将顺序更改为:(_b a c d č请注意,č现在位于末尾,而不是在c和之间,d因为它应该是)。

有什么办法可以实现这个目标吗?

请注意,我还关心除下划线之外的其他字符,即我想a-n.pdf a-p.pdf a.pdf c č d按此顺序排序而不是a-n.pdf a.pdf a-p.pdf c č d。 (编辑:实际上,a.pdf a-n.pdf a-p.pdf c č d也可以,只要不忽略非字母数字字符。)

以下不是我正在寻找的答案:

  • LC_COLLATE=C如上所述使用,
  • 使用 shell 扩展,例如ls _*; ls [^_]*因为问题不仅仅是关于下划线。

答案1

在 GNU 系统上,将 NUL 附加到非 alpha 可能会有所帮助:

$ ls | sed 's/[^[:alpha:]]/&\x0/g' | sort | tr -d '\0'
_b
a
c
č
d

假设文件名不包含换行符。通常,您无法对文件名列表进行排序,sort因为文件名本身很可能由多行组成。

在排序之前,您可以将文件名中的换行符替换为/此处。和zsh

print -rNC1 -- *(N) | # print NUL-delimited
  tr '\n\0' '/\n' |
  sed 's/[^[:alpha:]]/&\x0/g' |
  sort |
  tr -d '\0' |
  tr '/' '\n'

或者将列表保留为 NUL 分隔,以便可以对其进行后处理:

print -rNC1 -- *(N) | # print NUL-delimited
  tr '\n\0' '/\n' |
  sed 's/[^[:alpha:]]/&\x0/g' |
  sort |
  tr -d '\0' |
  tr '/\n' '\n\0'

strcoll()用于排序的 API 采用两个以 NUL 结尾的字符串。传统sort实现仅支持文本输入,并且文本输入排除了 NUL,因此它们没问题。然而, GNUsort与大多数标准文本实用程序的 GNU 实现一样,确实支持 NUL 及其输入。

我不知道 GNU 究竟如何sort处理带有 NUL 的行,但我的猜测是它会打破 NUL 上的行并将段一对一进行比较。所以,举例来说,foo_\0car比较时,先比较,再比较。foobar_\0morefoo_foobar_

zsh您还可以使用带有oeorder 基于e某些代码的评估)或o+functionglob 限定符的任意转换来定义 glob 的顺序。但在打电话之前strcoll()zsh删除 NUL,因此您不能使用与sort上面的 GNU 相同的转换。

相反,您可以0在非 alpha 序列之前添加 s,1在 alpha 序列之前添加 s:

~/.zshrc

set -o extendedglob
mysort() {
  REPLY=${REPLY//(#m)[^[:alpha:]]##/0$MATCH}
  REPLY=${REPLY//(#m)[[:alpha:]]##/1$MATCH}
}

然后:

$ print -rC1 -- *(No+mysort)
_b
a
c
č
d

相关内容