在不使用-S选项的情况下对ls -alh的输出值进行排序

时间:2017-01-08 19:27:52

标签: linux bash shell sorting

我有一个递归遍历目录的脚本,并将运行ls -alh --block-size=KB | grep ^\-的结果附加到文件中。然后,我需要通过减小文件大小来对结果文件进行排序,就像使用-S选项一样,如果在调用ls时使用它。

2 个答案:

答案 0 :(得分:1)

Why you shouldn't parse the output of lsFixing Unix/Linux/POSIX Filenames很好地涵盖了尝试解析ls的许多问题,以便了解其他人在您面前的尝试。

您的方法无法可靠运行的其他一些原因:

  1. 如果你在一个设备边界上进行递归,ls的某些版本可能会添加一列来显示新的设备ID并抛弃你的排序和解析;
  2. 您正在使用sed删除ls -h输出的kB / mB / gB幅度。这将把2字节文件,2千字节文件和2兆字节文件排在一起,大小相同。
  3. ls的输出在您管道或在终端显示时也会发生变化,同时也会更改解析/排序的逻辑。
  4. 解决方案是使用glob并根据ls输出的添加列进行排序。

    我们可以使用dd创建一些已知大小的测试文件列表:

    dd if=/dev/zero of=A  bs=2  count=1
    dd if=/dev/zero of=B  bs=1024  count=2
    dd if=/dev/zero of=C  bs=1024  count=3
    dd if=/dev/zero of=D  bs=1024  count=150
    dd if=/dev/zero of=E  bs=1024  count=2000
    

    导致:

    $ ls -lh *
    -rw-r--r--  1 andrew  wheel     2B Jan  8 20:52 A
    -rw-r--r--  1 andrew  wheel   2.0K Jan  8 20:52 B
    -rw-r--r--  1 andrew  wheel   3.0K Jan  8 20:52 C
    -rw-r--r--  1 andrew  wheel   150K Jan  8 20:52 D
    -rw-r--r--  1 andrew  wheel   2.0M Jan  8 20:52 E
    

    如果您按ls开关对-S的输出进行排序:

    $ ls -lhS *
    -rw-r--r--  1 andrew  wheel   2.0M Jan  8 20:52 E
    -rw-r--r--  1 andrew  wheel   150K Jan  8 20:52 D
    -rw-r--r--  1 andrew  wheel   3.0K Jan  8 20:52 C
    -rw-r--r--  1 andrew  wheel   2.0K Jan  8 20:52 B
    -rw-r--r--  1 andrew  wheel     2B Jan  8 20:52 A
    

    您的方法会删除第五列中的M KB,然后对其进行排序。这将导致A,B和E一起排序。

    可能 粗略ls的输出进行排序,如下所示:

    $ ls -al | grep ^\- | sort -nrk 5
    -rw-r--r--   1 andrew  wheel  2048000 Jan  8 20:52 E
    -rw-r--r--   1 andrew  wheel   153600 Jan  8 20:52 D
    -rw-r--r--   1 andrew  wheel     3072 Jan  8 20:52 C
    -rw-r--r--   1 andrew  wheel     2048 Jan  8 20:52 B
    -rw-r--r--   1 andrew  wheel        2 Jan  8 20:52 A
    

    但是这不会产生你拥有的-h的输出......)

    正确的方法是使用带有glob的Decorate / Sort / Undecorate pattern

    for fn in *; do
        [ -f "$fn" ] || continue
        c1=$(($(wc -c < "$fn")))
        c2=$(ls -alh "$fn")
        printf "%s\t%s\n" "$c1" "$c2"
    done | sort -nrk 1 | cut -f 2   
    

    结果:

    -rw-r--r--  1 andrew  wheel   2.0M Jan  8 20:52 E
    -rw-r--r--  1 andrew  wheel   150K Jan  8 20:52 D
    -rw-r--r--  1 andrew  wheel   3.0K Jan  8 20:52 C
    -rw-r--r--  1 andrew  wheel   2.0K Jan  8 20:52 B
    -rw-r--r--  1 andrew  wheel     2B Jan  8 20:52 A
    

    与使用ls -lhS

    相同

    如果要递归文件树并写入文件,则一般方法是相同的。

答案 1 :(得分:0)

我的解决方案对我的目的来说足够好,尽管接受的答案要好得多:

sed 's/kB//' files.tmp > files1.tmp #remove first instance of "kB" from each line
sed 's/ \+/ /g' files1.tmp > files2.tmp #replace all multiple spaces with single space
sort -k 5n,5 files2.tmp | tac > files3.tmp #sort by numeric file size and reverse

这仅适用于向--block-size=KB提供ls选项。