在不区分大小写的情况下,如何使“ ls”首先显示点文件?


21

在目录中创建以下文件。

$ touch .a .b a b A B 你好嗎

我的默认ls顺序忽略了前导点的存在,将它们与其他文件混合在一起。

$ ls -Al
total 0
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 A
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 B
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:06 你好嗎

可以 更改 LC_COLLATE为将点文件放在第一位。

$ LC_COLLATE=C ls -Al
total 0
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 .b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 A
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 B
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 a
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:03 b
-rw-r--r-- 1 sparhawk sparhawk 0 Jun  8 17:06 你好嗎

不幸的是,这使得排序顺序区分大小写,即AB普瑞森ab。有没有一种方法在不区分大小写的情况下(A以及before 和)a先打印点文件?Bb

编辑:尝试修改LC_COLLATE

到目前为止,没有一个答案能完全复制easy的功能ls。可以想象,我可以将其中的一些包装在一个函数中,但这将必须包含一些详细的代码,例如关于不带参数的工作方式与提供目录作为参数的方式。或如何处理显式-d标志。

另外,我认为也许可以LC_COLLATE使用更好。但是,我似乎无法完成这项工作。我目前正在使用LC_COLLATE="en_AU.UTF-8"。我检查了一下/usr/share/i18n/locales/en_AU(尽管我不确定这是否是正确的文件,因为我看不到任何引用UTF-8);我发现了以下内容。

LC_COLLATE
copy "iso14651_t1"
END LC_COLLATE

/usr/share/i18n/locales/iso14651_t1包含copy "iso14651_t1_common"。最后/usr/share/i18n/locales/iso14651_t1_common包含

 <U002E> IGNORE;IGNORE;IGNORE;<U002E> # 47 .

我删除了这一行,运行sudo locale-gen,然后重新启动计算机。不幸的是,这并没有改变。

Answers:


11

OP与编辑非常接近/usr/share/i18n/locales/iso14651_t1_common,但诀窍不是删除

<U002E> IGNORE;IGNORE;IGNORE;<U002E> # 47 .

而是将其修改为

<U002E> <RES-1>;IGNORE;IGNORE;<U002E> # 47 .

为什么这样做

IGNORE语句指定在<U002E>按字母顺序对单词进行排序时,将忽略句号(aka句点或character )。要使您的点文件排在首位,请更改IGNORE为在所有其他字符之前的排序符号。整理符号由类似

collating-symbol <something-inside-angle-brackets>

它们是按行的外观排序的

<something-inside-angle-brackets>

在我的副本中iso14651_t1_common,第一位排序规则符号是<RES-1>,出现在第3458行。如果文件不同,请使用首先排序的排序规则符号。

有关使用LC_COLLATE进行字符排序的详细信息

<U002E>之所以有3条IGNORE陈述,是因为在有联系的情况下可以多次比较字母。要理解这一点,请考虑小写a和大写A(它们是实际上被比较四次的一组字符的一部分):

<U0061> <a>;<BAS>;<MIN>;IGNORE # 198 a
<U0041> <a>;<BAS>;<CAP>;IGNORE # 517 A

进行多轮比较可以使以“ a”和“ A”开头的文件归为一组,因为与<a>第一次通过时一样,两者都进行了比较,下一个字母确定了顺序。如果以下所有字母都相同(例如a.txtA.txt),则第三遍将排在a.txt第一位,因为小写字母的校对符号<MIN>出现在第3467行,大写字母的校对符号之前<CAP>(第3488行)。

实施此更改

如果希望每次程序使用来订购字母首先出现句号LC_COLLATE,则可以iso14651_t1_common如上所述进行修改并重建位置文件。但是,如果你想使这一变化ls和无根的访问,可以将原有的语言文件修改之前复制到另一个目录。

我做了什么

我的默认语言环境是en_US,所以我复制en_USiso14651_t1以及iso14651_t1_common$HOME/path/to/new/locales。在那里,我对进行了上述更改,iso14651_t1_common并将其重命名en_USen_DOTFILE。接下来,我使用编译了en_DOTFILE语言环境

localedef -i en_DOTFILE -f UTF-8 -vc $HOME/path/to/new/locales/en_DOTFILE.UTF-8

要替换默认的ls顺序,请制作一个名为的BASH脚本ls

#!/bin/bash
LOCPATH=$HOME/path/to/new/locales LANG=en_DOTFILE.UTF-8 ls "$@"

将其保存/usr/bin在路径上之前出现的位置,并使用使其可执行chmod +x ls


当然,您必须添加-a或-A来查看您的点文件,但是除非您始终希望查看它们,否则在命令行而不是在BASH脚本中进行操作是有意义的
beandip

辉煌!谢谢,这太完美了!我只是修改了根目录拥有的文件,所以没有测试您的脚本。但是,我认为您需要在前后加上双引号$@
Sparhawk

好电话-添加双引号
beandip

11

您可以改用Shell的排序顺序(可能不涉及语言环境的排序顺序;bash,AT&T kshyashtcshzsh产生预期的结果,mkshdash不要fish似乎给不区分大小写的顺序,但给人当有非ASCII不同的结果字符):

ls -dUl -- .* *

这给出ls了要列出的文件(和目录)的显式列表,并取消了ls的排序(-U,这是GNU扩展名)。

根据您使用的外壳,有一些警告。

  • zsh,则默认nomatch选项将导致该命令失败,如果该目录同时不包含隐藏文件和非隐藏文件;您可以禁用nomatch以避免这种情况,但是更好的方法是改为这样做set -o cshnullglob(并且只有在没有任何glob匹配(例如在(t)csh早期Unix shell中匹配)时命令才会失败)。
  • 使用zshpdksh及其衍生词和fish.*的扩展不包括...,因此匹配ls -Al。与其他贝壳...包括这样它匹配ls -al。在后一种情况下,您需要更改通配符模式以排除...ls -dUl -- ..?* .[!.]* *)。
  • 除了在fish(t)csh或者zsh,如果有任何匹配模式不匹配任何东西,ls会产生一个错误信息; 您可以通过设置nullglob选项(in bashzsh至少)或重定向stderr/dev/nullls -dUl -- ..?* .[!.]* * 2>/dev/null)来避免这种情况。如果您使用nullglob,请当心可能引起意外的行为(请参阅 Shell吃掉“?”字符)。fish行为像bashnomatch不同之处在于互动时,一条警告消息会为一个没有匹配每个水珠发行。

(感谢StéphaneChazelas的所有反馈!)


请注意,并非所有的shell都会使用语言环境的排序规则对列表进行排序。mkshdash例如将不排序不区分大小写。
斯特凡Chazelas

1
请注意-U(表示未排序)是GNU扩展。其他一些ls实现,例如FreeBSD都有一个,-U但不是用于未排序的列表。
斯特凡Chazelas

随着GNU ls,你需要--.*作为执行接受参数后选择(除非POSIXLY_CORRECT在环境中)
斯特凡Chazelas

偷偷摸摸(+1)!但是,我不确定在所有情况下(即在别名或函数中)如何轻松地使用它。例如,如果要指定特定目录ls作为参数,则必须更改。
Sparhawk

1
@PeterCordes [!.]是正确的。参见pubs.opengroup.org/onlinepubs/9699919799/utilities/…。一些(大多数?)shell可以^作为!否定字符类glob 的同义词。无论如何,我宁愿.[!.] .??* *.[!.]* ..?* *
rw32982支持Monica

4

您可以简单地使用两个单独的ls命令:

$ ls -dl ..?* .[^.]* 2>/dev/null ; ls -dl *
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 .a
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 .b
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 a
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 A
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 b
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 B
-rw-r--r--. 1 sparhawk sparhawk 0  8 Jun  09:29 你好嗎

与到目前为止的其他答案不同,此方法首先显示点文件,避免使用...条目,然后ls 按字母顺序显示其余条目。

@StephenKitt答案的答案可能有所改善,但可以达到相同的结果:

$ ls -dUl ..?* .[^.]* * 2>/dev/null

也是+1,但根据StephenKitt的回答,我不确定在所有情况下(即别名或函数中)如何轻松使用它。例如,如果要指定特定目录ls作为参数,则必须更改。(FWIW我正在使用zsh,但是我想这对bash人很有用。)
Sparhawk

-2

您可以使用ls命令选项进行播放。尝试这个:

# ls -laXr

哪里:

-l     use a long listing format
-a, --all
              do not ignore entries starting with .
-X     sort alphabetically by entry extension
-r, --reverse
              reverse order while sorting

抱歉,这似乎不符合我的要求。该-X标志按后面的扩展名排序.,这是完全不同的。此外,文件按字母相反的顺序排列。另外,虽然在我的示例中首先使用了点文件,但并非在所有情况下都有效(例如a.b c.d .a .c)。另外,您已使用-a代替-A
Sparhawk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.