协慌网

登录 贡献 社区

rm,cp,mv 命令的参数列表过长错误

我在 UNIX 的目录下有几百个 PDF。 PDF 的名称非常长(约 60 个字符)。

当我尝试使用以下命令一起删除所有 PDF 时:

rm -f *.pdf

我收到以下错误:

/bin/rm: cannot execute [Argument list too long]

该错误的解决方法是什么? mvcp命令也会发生此错误吗?如果是,如何解决这些命令?

答案

发生这种情况的原因是 bash 实际上将星号扩展到了每个匹配的文件,从而产生了很长的命令行。

试试这个:

find . -name "*.pdf" -print0 | xargs -0 rm

警告:这是递归搜索,还将在子目录中查找(和删除)文件。仅在确定不希望确认时,才将-f

您可以执行以下操作使命令非递归:

find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm

另一种选择是使用 find 的-delete标志:

find . -name "*.pdf" -delete

tl; dr

这是命令行参数大小的内核限制。请使用for循环。

问题的根源

这是一个系统问题,与execveARG_MAX常数有关。有很多关于此的文档(请参阅debian 的 wiki man execve )。

基本上,扩展产生的命令(及其参数)超过ARG_MAX限制。在内核2.6.23 ,该限制设置为128 kB 。该常量已增加,您可以通过执行以下操作获取其值:

getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic

解决方案:使用for循环

按照 BashFAQ / 095的建议使用for循环,并且除了 RAM / 内存空间外没有其他限制:

空运行以确定其将删除您的期望:

for f in *.pdf; do echo rm "$f"; done

并执行它:

for f in *.pdf; do rm "$f"; done

这也是一种可移植的方法,因为 glob 在 shell 之间具有强大且一致的行为( POSIX 规范的一部分)。

注意:正如一些评论所指出的那样,这确实较慢,但更易于维护,因为它可以适应更复杂的场景,例如,一个人想做的不只是一项动作。

解决方案:使用find

如果您坚持要使用,则可以使用find但实际上不要使用 xargs,因为它“在读取非 NUL 分隔的输入时是危险的(损坏,可利用等)”

find . -maxdepth 1 -name '*.pdf' -delete

使用-maxdepth 1 ... -delete代替-exec rm {} +可以使find自己简单地执行所需的系统调用,而无需使用外部进程,因此速度更快(感谢@chepner comment )。

参考

find具有-delete操作:

find . -maxdepth 1 -name '*.pdf' -delete