如何分类人类可读的大小


11

我基本上是在寻找文件,然后按大小排序。如果我不按照人类可读的大小对脚本进行排序,那么该脚本就可以工作。但我希望尺寸能被人类读取。如何排序人类可读的尺寸?

例如:

 ls -l | sort -k 5 -n | awk '{print $9 " " $5}'

这按预期工作,我得到的文件大小以字节为单位递增:

1.txt 1
test.txt 3
bash.sh* 573
DocGeneration.txt 1131
andres_stuff.txt 1465
Branches.xlsx 15087
foo 23735
bar 60566
2016_stuff.pdf 996850

现在,我希望该大小能被人类读取,因此我在ls中添加了-h参数,现在某些文件出现了故障:

 ls -lh | sort -k 5 -n | awk '{print $9 " " $5}'
1.txt 1
DocGeneration.txt 1.2K
andres_stuff.txt 1.5K
test.txt 3
Branches.xlsx 15K
foo 24K
bar 60K
bash.sh* 573
2016_stuff.pdf 974K


-k 5- 这是如何运作的?
ctrl-alt-delor

@ ctrl-alt-delor:我相信大小在ls输出的第5列
jesse_b

2
使用du代替ls可能是一个好主意。
xenoid

...或find-printf%p%s格式化器(后跟一个尺寸的‘人源化’)。
Stephen Kitt

@Jesse_b是我的错误,我只是假设问题中的数据(标记为我得到的)是已排序的输入。我错了。
ctrl-alt-delor

Answers:


28

尝试 sort -h k2

-h,-human-numeric-sort比较人类可读的数字(例如2K 1G)

它是gnu sort,BSD sort等的一部分。


5
不应该避免解析输出ls吗?

3
@Tomasz并非总是如此。如果它提供所需的输出,则将其通过管道传输到另一个格式化操作并不是特别危险。您不应该在的输出上循环ls,而是直接使用文件遍历。独自一人无法在这里工作。话虽如此,我可能更愿意du这样做。
Bloodgain

1
@Bloodgain不能保证ls格式在系统/ l二进制文件中是相同的,因此,认为可移植地解析它是不可能的。
D. Ben Knoble

1
此外,带空格的文件名也会使内容
混乱

1
@Bloodgain :(files=(); for f in *; do [[ -L "$f" ]] && files+=("$f"); done; echo ${#files[@]}我可能有一个符号链接测试开关错误)。如果您不关心符号链接,files=(*); echo ${#files[@]}则在使用set而不是数组时可移植。
D. Ben Knoble

29

ls内置了此功能,请使用-S选项并以相反的顺序排序:ls -lShr

       -r, --reverse
              reverse order while sorting

       -S     sort by file size, largest first

1
-h不是标准ls选项,但必须在OP已经拥有的情况下可用。其余的都是标准的,这肯定是我会写的答案。
Toby Speight

5
+1不要乱分析的输出ls
David Richerby

这是最好的答案,但应在@Toby的注释中包含信息:-S可能不适用于您ls-S即使Emacs的库也支持FWIW,ls-lisp.el该库在OS没有时使用ls。例如,它可以在MS Windows的Emacs中工作。
Drew

这应该是公认的答案。
散布

1
@Drew:Toby的评论说这-h可能不是普遍可用的,但是OP无论如何已经在使用它。-S实际上应该是通用的,因为它在Toby提供的POSIX链接中。但是,确实存在许多非POSIX工具包。
凯文

5

由于未提及任何特定的shell,因此以下是在shell中执行整个操作的方法zsh

ls -lhf **/*(.Lk-1024oL)

**glob模式匹配一样*,但对面/的路径名,即像一个递归搜索会做。

ls命令将使用启用人类可读的大小-h,并使用启用长列表输出格式-l。该-f选项禁用排序,因此ls将仅按照文件的顺序列出文件。

该顺序由**/*(.Lk-1024oL)文件名遍历模式安排,因此较小的文件将首先列出。该**/*位与该目录及此目录下的每个文件和目录匹配,但是(...)修改了glob的行为(这是“ glob限定符”)。

这是oL在年底的订单(o)按文件大小的名字(L“长度”)。

.一开始让水珠只匹配常规文件(无目录)。

Lk-1024位选择大小小于1024 KB(“以KB表示的长度小于1024”)的文件。

如果zsh不是您的主要交互式外壳,则可以使用

zsh -c 'ls -lf **/*(.Lk-1024oL)'

使用setopt GLOB_DOTS(或zsh -o GLOB_DOTS -c ...)还可以匹配隐藏的名称。...或仅添加D到glob限定符字符串中。


在上面的内容上进行扩展,假设您想要一个2列的输出,该输出具有路径名和人类可读的大小,并且还假设您具有numfmtGNU coreutils的功能,

zmodload -F zsh/stat b:zstat

for pathname in **/*(.Lk-1024oL); do
    printf '%s\t%s\n' "$pathname" "$(zstat +size "$pathname" | numfmt --to=iec)"
done

或者更快

paste <( printf '%s\n' **/*(.Lk-1024oL) ) \
      <( zstat -N +size **/*(.Lk-1024oL) | numfmt --to=iec )

4

如果您sort没有该-h选项,则可以使用(虽然很长)awk命令,如下所示:

find . -type f -size -1024k -exec ls -al {} \; | sort -k 5 -n | awk '{if ($5 > 1099511627776) {print $9,$5/1024/1024/1024/1024"T"} else if ($5 > 1073741824) {print $9,$5/1024/1024/1024"G"} else if ($5 > 1048576) {print $9,$5/1024/1024"M"} else if ($5 > 1024) {print $9,$5/1024"K"} else {print $9,$5"B"}}' | column -t

这将以字节为单位对输出进行排序,然后将它们转换为人类可读的大小。


-1

这行得通吗?

ls -l | awk '{if ($5<=1024) {print}}' | sort -k 5 -n | awk '{print $9"\t"substr($5/1024,1,3)"k"} '| column -t

第一个awkexp将查找小于1M的文件,第二个exp将从结果中获取字节大小,并将其转换为KB,并打印前3个元素以提供人类可读的大小。


但这并不能真正解决OP的问题-它只会在当前目录中查找,并且只会打印常规文件。还将与1Kb而不是1MB进行比较。最后,我们在回答之后对代码为什么起作用进行了一些解释。
grochmal

我的坏人补充了它的作用。
Vignesh SP
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.