【问题标题】:Unix (Solaris) sort of ls -l output, with numeric namesUnix (Solaris) 类型的 ls -l 输出,带有数字名称
【发布时间】:2012-08-21 14:37:24
【问题描述】:

给定一个ls -l 目录列表,这些目录是软件发布版本,如何分类为人类喜欢的形式?例如:

$ ls -loghF 共计 209 drwxr-xr-x 2 18 年 6 月 3 日 11:33 12.0.40.0/ drwxr-xr-x 2 8 月 24 日 14:45 13.0.11.10/ drwxr-xr-x 2 13 年 7 月 3 日 14:12 13.0.11.4/ drwxr-xr-x 2 7 月 26 日 15:30 13.0.11.5/ drwxr-xr-x 2 7 月 27 日 11:33 13.0.11.6/ drwxr-xr-x 2 月 3 日 8 月 3 日 11:41 13.0.11.7/ drwxr-xr-x 2 10 年 8 月 3 日 11:53 13.0.11.8/ drwxr-xr-x 2 17 年 8 月 3 日 17:00 13.0.11.9/ drwxr-xr-x 2 8 月 3 日 14:37 13.0.17.0/ drwxr-xr-x 2 13 年 8 月 3 日 11:50 13.0.18.0/ drwxr-xr-x 2 17 年 8 月 3 日 11:21 13.0.19.0/ drwxr-xr-x 2 7 月 28 日 15:00 13.0.9.1/

想要的结果是:

$ ls -loghF |种类 ... 共计 209 drwxr-xr-x 2 18 年 6 月 3 日 11:33 12.0.40.0/ drwxr-xr-x 2 7 月 28 日 15:00 13.0.9.1/ drwxr-xr-x 2 13 年 7 月 3 日 14:12 13.0.11.4/ drwxr-xr-x 2 7 月 26 日 15:30 13.0.11.5/ drwxr-xr-x 2 7 月 27 日 11:33 13.0.11.6/ drwxr-xr-x 2 8 月 3 日 11:41 13.0.11.7/ drwxr-xr-x 2 10 年 8 月 3 日 11:53 13.0.11.8/ drwxr-xr-x 2 17 年 8 月 3 日 17:00 13.0.11.9/ drwxr-xr-x 2 8 月 24 日 14:45 13.0.11.10/ drwxr-xr-x 2 8 月 3 日 14:37 13.0.17.0/ drwxr-xr-x 2 13 年 8 月 3 日 11:50 13.0.18.0/ drwxr-xr-x 2 17 年 8 月 3 日 11:21 13.0.19.0/

排序必须跳过每行的日期部分,然后使用“.”按数字排序(例如,从 12 或 13 开始)作为字段分隔符。

我想到了两种方法,但是如果完全支持 sort -k 语法,我会遇到困难:

(1) 跳过前 36 个字符,然后使用 '.'作为字段分隔符,对接下来的 4 个字段进行数字排序。

(2) 以字段分隔符为空格,跳到第7个字段,然后将字段分隔符更改为'.'并对接下来的 4 个字段进行数字排序。

替代方案是一个小的 Perl 脚本,但 Unix 排序不能完成这个“简单”任务吗?

【问题讨论】:

    标签: unix sorting ls


    【解决方案1】:

    仅供参考:这就是我最终做的事情。
    特别鸣谢:http://www.sysarch.com/Perl/sort_paper.html

    $ ls -loghF | perl -e '
    use strict;
    my @in = <>;
    my @out = grep(m|\d+\.\d+\.\d+\.\d+/$|, @in);
    print sort {
        my @aa = $a =~
                m|(\d+)\.(\d+)\.(\d+)\.(\d+)/$|;
        my @bb = $b =~
                m|(\d+)\.(\d+)\.(\d+)\.(\d+)/$|;
        $aa[0] <=> $bb[0] or
        $aa[1] <=> $bb[1] or
        $aa[2] <=> $bb[2] or
        $aa[3] <=> $bb[3]
        } @out;
    '
    
    drwxr-xr-x 2 18 年 6 月 3 日 11:33 12.0.40.0/ drwxr-xr-x 2 7 月 28 日 15:00 13.0.9.1/ drwxr-xr-x 2 13 年 7 月 3 日 14:12 13.0.11.4/ drwxr-xr-x 2 7 月 26 日 15:30 13.0.11.5/ drwxr-xr-x 2 7 月 27 日 11:33 13.0.11.6/ drwxr-xr-x 2 月 3 日 8 月 3 日 11:41 13.0.11.7/ drwxr-xr-x 2 10 年 8 月 3 日 11:53 13.0.11.8/ drwxr-xr-x 2 17 年 8 月 3 日 17:00 13.0.11.9/ drwxr-xr-x 2 8 月 24 日 14:45 13.0.11.10/ drwxr-xr-x 2 8 月 29 日 17:31 13.0.11.11/ drwxr-xr-x 2 8 月 3 日 14:37 13.0.17.0/ drwxr-xr-x 2 13 年 8 月 3 日 11:50 13.0.18.0/ drwxr-xr-x 2 17 年 8 月 3 日 11:21 13.0.19.0/

    【讨论】:

    • 早期的 awk 解决方案作为单行命令更好,但我使用上面的解决方案是因为我在另一个 Perl 脚本的上下文中运行 run,所以 Perl 的东西已经可用了。
    【解决方案2】:

    这是一个命令行,它使用awk 将版本号放在第一位,使用四个数字键排序,然后使用cut 去掉前面的临时:

    $ ls -loghF | awk '{ print $7, $0; }' | sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4 | cut -d' ' -f2-
    drwxr-xr-x   2       3 Jun 18 11:33 12.0.40.0/
    drwxr-xr-x   2       3 Jul 28 15:00 13.0.9.1/
    drwxr-xr-x   2       3 Jul 13 14:12 13.0.11.4/
    drwxr-xr-x   2       3 Jul 26 15:30 13.0.11.5/
    drwxr-xr-x   2       4 Jul 27 11:33 13.0.11.6/
    drwxr-xr-x   2       3 Aug  3 11:41 13.0.11.7/
    drwxr-xr-x   2       3 Aug 10 11:53 13.0.11.8/
    drwxr-xr-x   2       3 Aug 17 17:00 13.0.11.9/
    drwxr-xr-x   2       3 Aug 24 14:45 13.0.11.10/
    drwxr-xr-x   2       3 Aug  3 14:37 13.0.17.0/
    drwxr-xr-x   2       3 Aug 13 11:50 13.0.18.0/
    drwxr-xr-x   2       3 Aug 17 11:21 13.0.19.0/
    

    那里的排序命令是从this answer借来的。另一个答案建议sort -V(版本排序),但我的sort 版本没有它(不过你的可能,所以值得一试)。版本排序可能特定于较新的 GNU coreutils(我的 Linux 机器有它,排序来自 GNU Coreutils 8.5)。

    带版本排序:

    $ ls -loghF | sort -k7,7V
    drwxr-xr-x   2       3 Jun 18 11:33 12.0.40.0/
    drwxr-xr-x   2       3 Jul 28 15:00 13.0.9.1/
    drwxr-xr-x   2       3 Jul 13 14:12 13.0.11.4/
    drwxr-xr-x   2       3 Jul 26 15:30 13.0.11.5/
    drwxr-xr-x   2       4 Jul 27 11:33 13.0.11.6/
    drwxr-xr-x   2       3 Aug  3 11:41 13.0.11.7/
    drwxr-xr-x   2       3 Aug 10 11:53 13.0.11.8/
    drwxr-xr-x   2       3 Aug 17 17:00 13.0.11.9/
    drwxr-xr-x   2       3 Aug 24 14:45 13.0.11.10/
    drwxr-xr-x   2       3 Aug  3 14:37 13.0.17.0/
    drwxr-xr-x   2       3 Aug 13 11:50 13.0.18.0/
    drwxr-xr-x   2       3 Aug 17 11:21 13.0.19.0/
    

    【讨论】:

    • Solaris sort 不太可能有版本号或“自然”排序等选项。
    • “自然”排序是什么意思?请注意,GNU coreutils 可以安装在很多机器上,因此在 Solaris 上拥有sort -V 并非不可能。
    • natural-sort 的例子。另见Coding Horror。等等。
    • 当然可以在机器上添加GNU coreutils;但是你永远不会在 Solaris 上的/usr/bin 中投入那么多,如果你重视你的理智的话。不要在任何机器上触摸/bin/usr/bin,除非您非常确信系统提供的每个脚本都会对更改后的命令语义感到满意。
    • 谢谢大家,但如果我必须编写脚本,我将使用 Perl - 不用 awk'ing。 sort 可以直接处理吗?看来关键是,如何使用多个字段分隔符,或者将字段分隔符与数字字段计数器结合起来。
    【解决方案3】:

    这不是最快的方法,但解释起来相当简单:

    ls -loghF |
    awk '{ print $7 " " $0 }' |
    sort -t. -k 1,1n -k 2,2n -k3,3n -k 4,4n |
    sed 's/^[^ ]* //'
    

    'awk' 命令将目录字段复制到行首; sort 命令仅使用单个分隔符(.;我认为您不能对行的不同部分使用不同的分隔符),然后按数字顺序显式对 4 个数字部分进行排序。然后sed 去掉前面添加的字段。

    这是“让sort 轻松找到密钥”的简单版本,因为拆分输入是sort 中昂贵的操作之一。

    【讨论】:

      猜你喜欢
      • 2011-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-27
      • 1970-01-01
      • 2015-06-07
      • 1970-01-01
      • 2014-10-10
      相关资源
      最近更新 更多