列出按数字排序的文件


122

我有一堆文件,从log1log164

我正在尝试在UNIX终端中列出目录(已排序),但是sort函数仅提供如下格式:

home:logs Home$ ls -1 | sort
log1.gz
log10.gz
log100.gz
log101.gz
log102.gz
log103.gz
log104.gz
log105.gz
log106.gz
...etc

我想要的是

home:logs Home$ ls -1 | sort
log1.gz
log2.gz
log3.gz
log4.gz
log5.gz
log6.gz
log7.gz
...{more here}
log99.gz
log100.gz
log101.gz
log102.gz
...etc

有什么建议可以用来做这件事吗?


8
这绝对是一个编程问题,不应仅仅因为答案涉及低壳的编程语言而就不应该迁移!
tchrist 2012年

如果您事先知道它们是log1.gz通过命名的log164.gz,那么您甚至需要ls -1它们做什么?
ruakh 2012年

1
@ruakh ls -1将结果显示在一列中,而不是在整个列中显示

3
@ Rabiani:我知道是什么ls -1:它列出了文件名。由于您已经知道文件名,因此我不明白您需要什么文件名。但既然你已经接受凯文的回答,我现在知道了:你没有需要它。这更有意义。:-)
ruakh 2012年

Answers:


40

bash的花括号,{}将按顺序枚举:

for file in log{1..164}.gz; do
    process "$file"
done

266

为什么不ls为此特定情况使用内置功能,即

-v natural sort of (version) numbers within text

例如 ls -1v log*


很棒的解决方案,尽管我希望使用同样简单的解决方案sort,以防万一有一个字符串数组而不是一个文件目录
Hubro 2015年

23
在BSD / OSX上,此选项是其他选项:-v - Force unedited printing of non-graphic characters
kenorb

不幸的是,-v选项在AIX(6.1)上不可用
bouvierr '16

6
这应该是最好的答案。
32r34wgf3e

1
对于MacOS,它将起作用,找不到如上所述的选项,只有ls | sort -n
Ricky Levi,

47

使用GNU ls(即在Linux,Cygwin或其他专门安装了GNU ls的系统上):

ls -v

在zsh中:

echo *(n)

在其他shell中:

echo log?.gz log??.gz log???.gz

如果要将每个文件名放在单独的行中,请替换echoprintf '%s\n'

如果您还需要文件元数据(ls -l),并且没有GNU ls,则需要ls分别按字典顺序对要查看的每个文件名或文件名组进行调用。

ls -ld log?.gz; ls -ld log??.gz; ls -ld log???.gz

为避免这些困难,请在文件名中使用足够的前导零,以使词典编排排序对人类友好(log001.gz,等)。


29

虽然ls -1v在此特定情况下解决方案当然是最好的,但我认为也可以sort像原始问题中那样使用它,这是很好的,因为当您的输入不来自时也可以使用ls。在这种情况下,您可以使用:

ls -1 | sort -n -k1.4

-n选项指示sort进行数字排序,并将-k 1.4sort键设置为第一个字段(在本例中为整个文件名),从第4个字符到最后一个字符。


就我而言,ls -1 | sort -n -k1.4不起作用。它首先给出未排序的字符,最多4个字符,然后在第4个字符之后给出已排序的字符。我ls -1 |sort | sort -n -k1.4改为使用它,并且效果很好。
Prabhu 2014年

3
@Prabhu,您可以这样做sort -k1.1,1.3 -k1.4nsort实施不一定要稳定,因此您的方法不适用于所有实施。另请参见-VGNU和FreeBSD 的选项sort
斯特凡Chazelas

21

GNU sort(在Linux上可用)具有“版本排序”模式,该模式可以按照您要求的方式解释非数字中的数字:

来自man 1 sort

    -V, --version-sort
           natural sort of (version) numbers within text

(创建空的测试文件清单:
touch log1.gz log2.gz log3.gz log99.gz log100.gz log101.gz log102.gz

您的示例案例中,添加了-V选项(或--version-sort):

ls -1 log*.gz | sort -V
log1.gz
log2.gz
log3.gz
log99.gz
log100.gz
log101.gz
log102.gz


3

我的Solaris版本不支持ls -v(grrr)。上面提供的排序解决方案1)要求知道文件名中数字的位置,并且2)不处理诸如多部分版本号之类的事情。

下面的方法与Solaris兼容,不需要预先知道数字的位置,并且处理具有2、3或4个组件的版本号(例如:a-1.2,foo-5.6.7,bar_baz_9.10.11.12)。它还用于sort -f将大写和小写折叠在一起,并正确处理与文件混合的目录:

ls -d | sort -f -t . -k 1,1 -k 2,2n -k 3,3n -k 4,4n

请注意,此版本将第一个组成部分限制为一个数字。

如果您的目标操作系统支持ls -v,那么这显然是高级的解决方案。


1

Perl解决方案:

ls log*.gz | perl -ne 'sub getnum{ $_[0] =~ /log(\d+)\.gz/; $1 }; push @A, $_; END{ print sort { getnum $a <=> $b } @A}'

1
$ ls
log101.gz  log102.gz  log103.gz  log104.gz  log105.gz  log106.gz  log10.gz  log1.gz
$ ls | sort -t . -n -k1.4
log1.gz
log10.gz
log101.gz
log102.gz
log103.gz
log104.gz
log105.gz
log106.gz

1
这里-t .是多余的。
斯特凡Chazelas

0

这对我有用。

我有文件1.jpg 2.jpg ... 18.jpg

$ echo *.jpg | tr -s ' ' '\n' | sort -n

sortls由于无法打印的颜色字符而使输出感到困惑。如果您尝试这样做:

ls -1 --color=none *.jpg | sort -n

它会完美地工作。

sort可以忽略带有-i选项的不可打印字符,但仍然无法正常工作,我也不知道为什么。

但是您总是可以像这样去除颜色,并且sort可以工作:

ls -1 --color=always *.jpg | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | sort -n

我希望有一天sort可以为此选择。

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.