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

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

rm -f *.pdf

我收到以下错误:

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

此错误的解决方案是什么?mv和cp命令是否也会出现此错误?如果是,如何解决这些命令?


当前回答

还有一个:

cd  /path/to/pdf
printf "%s\0" *.[Pp][Dd][Ff] | xargs -0 rm

printf是一个内置的shell,据我所知,它一直都是这样的。既然printf不是一个shell命令(而是一个内置命令),它就不会出现“参数列表太长…”致命错误。

因此,我们可以安全地将其与*等shell globbing模式一起使用。[Pp][Dd][Ff],然后我们通过xargs将其输出通过管道传输到remove(rm)命令,这确保它在命令行中适合足够的文件名,以免rm命令(shell命令)失败。

printf中的\0用作文件名的空分隔符,然后由xargs命令处理,使用它(-0)作为分隔符,因此当文件名中有空格或其他特殊字符时,rm不会失败。

其他回答

tl;博士

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

问题的根源

这是一个系统问题,与execve和ARG_MAX常量有关。有很多关于这方面的文档(参见man execve、debian的wiki、ARG_MAX详细信息)。

基本上,扩展生成的命令(及其参数)超过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注释)。

工具书类

我得到了“参数列表太长”。如何处理大块列表?@羊毛边的execve(2)-Linux手册页(搜索ARG_MAX);错误:参数列表太长@Debian的wiki;为什么在传递带引号的参数时会得到“/bin/sh:参数列表太长”?@超级用户

我只知道一个办法。这个想法是将你拥有的pdf文件列表导出到一个文件中。然后将该文件分成几个部分。然后删除每个部分中列出的pdf文件。

ls | grep .pdf > list.txt
wc -l list.txt

wc-l是计算list.txt包含的行数。当你知道它有多长时,你可以决定把它分成两半、四等分或其他什么。使用split-l命令例如,将其分成600行。

split -l 600 list.txt

这将创建一个名为xaa、xab、xac等的文件,具体取决于如何拆分它。现在,要将这些文件中的每个列表“导入”到命令rm中,请使用以下命令:

rm $(<xaa)
rm $(<xab)
rm $(<xac)

对不起,我的英语不好。

使用GNU并行(sudo apt install parallel)非常简单

它以多线程方式运行命令,其中“{}”是传递的参数

E.g.

ls/tmp/myfiles*|并行“rm{}”

我也遇到了同样的问题,因为一个文件夹中的临时图像与日俱增,这个命令帮助我清除了这个文件夹

find . -name "*.png" -mtime +50 -exec rm {} \;

与其他命令的不同之处在于mtime参数,该参数将只接受早于X天的文件(在示例中为50天)

多次使用这种方法,减少每天执行的次数,我能够删除所有不必要的文件

我在将源目录复制到目标目录时遇到了同样的问题

源目录包含文件约3 lakcs

我使用cp和选项-r,这对我很有用

cp-r abc/def/

它会将所有文件从abc复制到def,而不会发出参数列表过长的警告