说我想检查某个目录中每个文件的大小。
这是我所做的:
du -sh *
另外,我可以这样做:
ls | xargs du -sh
这两个命令执行完全相同的操作。
我想知道它们是否完全相同,例如它们的成本、效率等(我猜第一个命令比第二个命令轻?)
答案1
一个是正确的,另一个则不正确。
du -sh *
(应该du -sh -- *
避免以 开头的文件名出现问题-
)
依赖 shell 来扩展 glob *
;du
将当前目录中的所有非隐藏文件和目录视为单独的参数。这可以正确处理特殊字符。
ls | xargs du -sh
依赖于xargs
processls
的输出。xargs
将其输入拆分为空格(至少是空格、制表符和换行符,在某些实现中更多),还理解某种形式的引用,并du
使用每个空格分隔的字符串运行(一次(即使对于空输入)或多次调用)个别论点。
如果当前目录不包含名称中含有空格、单引号、双引号或反斜杠字符的文件,并且只有足够少的文件(但至少有一个)xargs
仅运行一次du
调用,则两者看起来是等效的,但它们是不是。
从效率上来说,du -sh *
使用一个流程,ls | xargs du -sh
至少使用三个流程。在一种情况下,管道方法可以工作,而 glob 则不行:如果当前目录中有太多文件,shell 将无法一次性du
使用所有文件名运行,但会xargs
以du
根据需要多次计算以覆盖所有文件,在这种情况下您会看到几行,并且具有多个硬链接的文件可能会被计算多次。
也可以看看为什么*不*解析`ls`?
1 如果当前目录中没有非隐藏文件,du -sh -- *
您的 shell 将会失败并出现错误,或者某些 shell(例如使用文字作为参数bash
运行)会抱怨该文件不存在。虽然使用,大多数实现(某些 BSD 除外)将在没有参数的情况下运行,因此给出当前目录的磁盘使用情况(因此还包括目录文件本身以及其中所有隐藏文件和目录的磁盘使用情况)du
*
du
*
ls | xargs du -sh --
xargs
du
答案2
在第一种情况下,shell 扩展*
为匹配文件名的列表,并将它们作为参数传递给du
命令。在第二种情况下,shell 启动两个通过管道连接的进程 (ls
和)。打印文件名并读取它们,然后启动命令。所以第二个版本执行 3 个命令,第一个版本只执行一个。存在一些潜在的差异:xargs
ls
xargs
du
ls
可能会以不同的顺序列出文件- 根据环境设置,
ls
甚至可能列出更多或更少的文件(但不确定) - 当
xargs
接收到的文件名多于可以作为参数传递的文件名时,它将执行du
多次