当我尝试时
du -sh $(sed -ne '/\.[hc]$/p' ../all-file)
它说
$ bash: /usr/bin/du: Argument list too long
然后我尝试
for i in $(sed -ne '/\.[hc]$/p' ../all-file); do du "$i"; done|vim -
但需要很长时间才能完成。
我怎样才能加快速度而不用大惊小怪?
答案1
您是否已经根据提供的评论弄清楚了这一点?
sed -ne '/\.[hc]$/p' ../all-file | xargs du -sh
虽然我质疑为什么不使用 grep ?速度至少快两倍。
grep '\.[hc]$' ../all-file | xargs du -sh
答案2
通过 GNU 实现du
,您可以执行以下操作:
<../all-file LC_ALL=C grep '\.[hc]$' |
tr '\n' '\0' |
du -sh --files0-from=-
通过 GNU 实现xargs
:
<../all-file LC_ALL=C grep '\.[hc]$' |
xargs -rd '\n' du -sh --
或者使用一些xargs
复制了 GNU 的其他实现-r
,-0
如果不是的话,-d
比如在大多数 BSD 上:
<../all-file LC_ALL=C grep '\.[hc]$' |
tr '\n' '\0' |
xargs -r0 du -sh --
但请注意,由于du
仅报告一次硬链接的磁盘使用情况,因此如果您像这样将列表分成几批xargs
,则最终可能会得到不同的结果。如果您想使用该-c
选项在最后获得累积结果,您还必须使用该--files0-from
方法。
例子:
$ seq 100000 > a.c
$ ln a.c b.c
$ du -shc a.c b.c
651K a.c
651K total
查看如何b.c
不报告,因为这实际上与a.c
.两个文件的累计磁盘使用量为 651K。
$ du -shc a.c; du -shc b.c
651K a.c
651K total
651K b.c
651K total
您得到 2 个总计 651K 的文件,这隐藏了 ac 和 bc 是同一个文件的事实。
另一方面,如果您想禁用硬链接处理,并通过 GNU 实现来单独报告每个文件的磁盘使用情况,du
则可以使用-l
/--count-links
选项。--apparent-size
如果您对文件的大小而不是其磁盘使用情况感兴趣,另请参阅该选项。
在现代版本的 Linux 上,您可以通过提高资源限制来提高参数 + 环境的大小限制stacksize
。
例如,使用:ulimit -s unlimited
在大多数 shell 中(也在limit stacksize unlimited
zsh 中,它仅适用于子进程),您可能能够超越限制并避免分解列表。
$ /bin/true {1..150000}
zsh: argument list too long: /bin/true
(127)$ limit stacksize unlimited
$ /bin/true {1..150000}
$ /bin/true {1..250000}
$ /bin/true {1..350000}
$ /bin/true {1..500000}
zsh: argument list too long: /bin/true
然后,您也许可以使用 split+glob,但与往常一样,您需要对其进行调整以将分隔符修复为仅换行符 ( IFS=$'\n'
) 并禁用您可能不想要的通配符 ( set -o noglob
):
(
ulimit -s unlimited
IFS=$'\n'
set -o noglob
du -sh -- $(<../all-file LC_ALL=C grep '\.[hc]$')
)
../all-file
需要注意的是,在没有与该模式匹配的行的情况下,您最终将du
在不带参数的情况下运行,这将默认获取当前工作目录的磁盘使用情况(可以-r
选择xargs
处理这些情况)。
还有一些注意事项:
sed -ne /re/p
是grep
(这是grep
缩写词,虽然来自ed
sg/re/p
)。- 文件路径可以由任何非 NUL 字节组成,为了能够表示它们的任意列表,一个明显的选择是用 NUL 分隔它们,因此
--files0-from
需要 NUL 分隔的列表。这意味着您的换行符分隔all-file
文件无法列出任意文件路径。这也意味着,由于文件路径不必由文本组成,因此不能保证使用文本实用程序处理它们能够正常工作,除非在 C 等所有字节都是字符的语言环境中。使用LC_ALL=C
也可能会提高性能,因为它避免了将字节解码为字符。 $(...)
bash 中不加引号的是 split+glob。如果您知道文件路径不包含全局字符也不包含$IFS
变量中的字符,则只能使用该文件列表来拆分文件列表。- 对于
xargs
没有-0
/ 的-d
情况,拆分是在空格或换行符上完成的,单/双引号和反斜杠被解释为转义运算符,这意味着它无法处理换行符分隔的任意文件路径列表,就像您all-file
看起来的那样。 - 当将变量、预先未知的参数列表传递给命令时,您需要确保
--
在它之前使用它来标记选项的结尾,以确保第一个(或任何具有 GNU 实现的)参数以-
(或+
对于某些命令),它不被视为一个选项。