【问题标题】:Using sort to rank a column by its size使用排序按列的大小对列进行排名
【发布时间】:2009-06-28 12:29:53
【问题描述】:

我需要你的帮助。 让我告诉你我的问题是什么。 我有一个文本文件如下:

Music 3.6G
Other 254.5M
Videos 4.6G
Games 1.3G
Apps 10.1G

如您所见,该文件有两列,由目录名称及其适当的大小组成。

我想要做的是按目录大小按降序对该文件进行排序,如下所示:

Apps 10.1G
Videos 4.6G
Music 3.6G
Games 1.3G
Other 254.5M

有没有办法做到这一点?是否有一个单行命令?

谢谢。

【问题讨论】:

  • 这个问题有多种解决方案:stackoverflow.com/questions/586033/…
  • 好吧,但我必须更改文本文件的内容..
  • 仅包含一个 4 KiB 文件的目录的输出是什么?包含 10.6 KiB 的文件?
  • ... 而且您不需要更改文件内容。您可以在内存或临时文件中执行此操作。

标签: shell directory sorting


【解决方案1】:

您需要在排序前标准化大小。最简单的方法是使用 Perl 或 Python 之类的编程语言,但您已经声明这不是一种选择(尽管我觉得奇怪的是 Perl 还没有在机器上)。您可以使用 shell 代码来规范化该数据,但这很麻烦:

#!/bin/bash

ECHO=/bin/echo
TR=/usr/bin/tr
BC=/usr/bin/bc

while read dir size; do
    bytes=`$ECHO $size | $TR -d "[A-Z]"`
    case $size in
        *B) bytes=$bytes                                      ;;
        *K) bytes=`$ECHO "$bytes * 1024" | $BC`               ;;
        *M) bytes=`$ECHO "$bytes * 1024 * 1024" | $BC`        ;;
        *G) bytes=`$ECHO "$bytes * 1024 * 1024 * 1024" | $BC` ;;
        *) $ECHO unknown size type                            ;;
    esac
    echo $bytes $dir $size
done < $1

此 shell 脚本接受文件名作为参数,并打印出标准化大小、目录名称和大小。这使得排序变得容易。要取回原来的字段,您可以只剪掉第一个字段:

./mk_sortable.sh file_to_sort | sort -nr | cut -f2- -d" "

对于那些关注的人,是的,我只是在 shell 中写了一个Schwartzian Transform

【讨论】:

    【解决方案2】:

    检查排序手册页。

    在下面的第三个字段(区号)上对文件进行排序:
    Jim Alchin 212121 西雅图
    比尔·盖茨 404404 西雅图
    史蒂夫·乔布斯 246810 内华达州
    Scott Neally 212277 洛杉矶
    $ sort -k 3,3 people.txt> sorted.txt

    按数字降序(反向)排序:
    $ 排序 -nr

    【讨论】:

      【解决方案3】:
      sort -n -r -k 2,2 file.txt
      

      -k 2,2 表示使用文件中的第二个字段作为排序字段。默认情况下,排序使用空格来分隔字段。如果字段上的后缀(您的示例中的 G 表示千兆字节)不同,这可能不起作用。

      【讨论】:

      • 字段上的好后缀是不同的:(我还没有写完整的列表
      【解决方案4】:

      从根本上说,您必须对数字进行非人化,对非人化的数字进行排序,然后从输出中删除非人化的数字。虽然您可能可以在一行中完成(特别是如果您编写了一个脚本来为您完成),但我认为它需要几行才能理解。

      正如 Drakosha 所说,How Can I Sort 'du -h' output by size 很好地解决了这些问题。

      【讨论】:

        【解决方案5】:

        使用 Perl:

        perl -nle'$G{$2}=$1 if/(\w+) (\d+\.?\d*)G/;$M{$2}=$1 if/(\w+) (\d+\.?\d*)M/;$K{$2}=$1 if/(\w+) (\d+\.?\d*)K/;END{print"$G{$_} ${_}G"for sort{$b<=>$a}keys%G;print"$M{$_} ${_}M"for sort{$b<=>$a}keys%M;print"$K{$_} ${_}K"for sort{$b<=>$a}keys%K;}' filename
        

        这里,filename 是一个包含上述数据的文件。上面的单行处理单元GMK

        使用eval 的另一个更短的实现:

        perl -nle'/(\w+) (\d+\.?\d*)(\w)/;eval"\$\$3{$2} = $1";END{for$u qw(G M K){eval"print\"\$\$u{$_} $_$u\""for sort{$b<=>$a}keys%{$u}}}' filename
        

        【讨论】:

        • 您使用的是什么类型的系统?
        • 更严重的是,脚本没有将 M 作为后缀处理。
        • @Jonathan Leffler:原帖是在我发布单行字后编辑的。不管怎样,谢谢你告诉我。
        • @Alan:很公平 - 改变问题是个问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-12
        • 2021-10-07
        • 2018-06-25
        • 1970-01-01
        相关资源
        最近更新 更多