3

最近我想统计下,家目录下各文件(夹)的硬盘占用情况,所以用了这个命令:
find -maxdepth 1 | xargs du -sh

返回的结果是,整个家目录的总大小,而不是预期的每个文件的大小。之后换用了find -maxdepth 1 -exec du -sh {} \;就能得出每个文件的大小。

为什么使用find | xargs得出的结果跟find -exec不一样呢?

一个问题是,我们为什么要使用xargs?xargs对find的标准输出做了什么处理?

以下面为例:

[lzx:~/.oh-my-zsh]¥ find -maxdepth 1 | xargs
. ./plugins ./templates ./.git ./README.textile ./oh-my-zsh.sh ./log ./.gitignore ./custom ./cache ./MIT-LICENSE.txt ./themes ./tools ./lib
[lzx:~/.oh-my-zsh]¥ find -maxdepth 1
.
./plugins
./templates
./.git
./README.textile
./oh-my-zsh.sh
./log
./.gitignore
./custom
./cache
./MIT-LICENSE.txt
./themes
./tools
./lib

默认情况下,xargs只是把\n转换成了空格。

所以find -maxdepth 1 | xargs du -sh
近似于:du -sh . ./plugins ./templates ./.git ./README.textile ./oh-my-zsh.sh ./log ./.gitignore ./custom ./cache ./MIT-LICENSE.txt ./themes ./tools ./lib
结果是6.8M,而不是独立计算每个文件夹的硬盘占用。

有趣的是,如果移除所有条目前面的./,得出的结果就是

du -s cache custom lib log MIT-LICENSE.txt oh-my-zsh.sh plugins README.textile templates themes tools .git .
924K cache
20K custom
72K lib
8.0K log
4.0K MIT-LICENSE.txt
4.0K oh-my-zsh.sh
2.0M plugins
8.0K README.textile
8.0K templates
572K themes
32K tools
3.2M .git
8.0K .

可见,使用find | xargsfind -exec之所以会得出不同的结果,du对命令行输入的处理方式也是原因之一。

再来看下find -exec是怎样的:
这里写了个argv.rb脚本,简单地输出命令行参数。

[lzx:~]¥ find ./code -exec ./argv.rb {} \;
["./code"]
["./code/test"]
["./code/test/package.json"]
["./code/test/public"]
["./code/test/public/javascripts"]
["./code/test/public/images"]
["./code/test/public/stylesheets"]
["./code/test/public/stylesheets/style.styl"]
["./code/test/public/stylesheets/style.css"]
["./code/test/views"]
["./code/test/views/user.ejs"]
["./code/test/views/index.ejs"]
["./code/test/views/error.ejs"]
["./code/test/models"]
["./code/test/models/User.js"]
...
[lzx:~]¥ find ./code | xargs ./argv.rb
["./code", "./code/test", "./code/test/package.json", "./code/test/public", "./code/test/public/javascripts", "./code/test/public/images", "./code/test/public/stylesheets", "./code/test/public/stylesheets/style.styl", "./code/test/public/stylesheets/style.css", "./code/test/views", "./code/test/views/user.ejs", "./code/test/views/index.ejs", "./code/test/views/error.ejs", "./code/test/models", "./code/test/models/User.js", ...]

可见find -exec是对每一个匹配的文件都执行了命令。

不过,如果不是以{} \;结尾({}会被替换成匹配的文件名),而是以{} +结尾,那么命令只会在最后执行一次。这类似于使用xargs的结果。

BTW,既然xargs只是简单地把\n变成空格,那么可能存在一些问题。比如文件名带空格,这时候xargs就给跪了。万一空格之后是-xx那样的内容,那就有得看了。当然通过指定\0作为分隔符,可以避免这种情况:

find . -maxdepth 1 -print0 | xargs -0 xxx

但是这么麻烦,还是坚持使用find . -exec xxx {} \;好了。

后记: 经别人指正,其实使用du -hd 1就能统计当前目录下各个文件(夹)占用的大小,无需使用find -maxdepth 1 -exec du -sh {} \;


spacewander
5.6k 声望1.5k 粉丝

make building blocks that people can understand and use easily, and people will work together to solve the very largest problems.


« 上一篇
gtest快速上手
下一篇 »
玩转Bash变量