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

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

rm -f *.pdf

我收到以下错误:

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

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


当前回答

您可以使用bash数组:

files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
    rm -f "${files[@]:I:1000}"
done

这样,它将以每一步1000个文件的批量擦除。

其他回答

我遇到过几次这个问题。许多解决方案将为每个需要删除的文件运行rm命令。这是非常低效的:

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

我最终编写了一个python脚本,根据文件名中的前4个字符删除文件:

import os
filedir = '/tmp/' #The directory you wish to run rm on 
filelist = (os.listdir(filedir)) #gets listing of all files in the specified dir
newlist = [] #Makes a blank list named newlist
for i in filelist: 
    if str((i)[:4]) not in newlist: #This makes sure that the elements are unique for newlist
        newlist.append((i)[:4]) #This takes only the first 4 charcters of the folder/filename and appends it to newlist
for i in newlist:
    if 'tmp' in i:  #If statment to look for tmp in the filename/dirname
        print ('Running command rm -rf '+str(filedir)+str(i)+'* : File Count: '+str(len(os.listdir(filedir)))) #Prints the command to be run and a total file count
        os.system('rm -rf '+str(filedir)+str(i)+'*') #Actual shell command
print ('DONE')

这对我来说非常有效。我能够在大约15分钟内清除一个文件夹中超过200万个临时文件。我从一点点代码中对tar进行了注释,这样任何一个对python一无所知的人都可以操作这段代码。

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:参数列表太长”?@超级用户

一个更短更可靠的呢?

for i in **/*.pdf; do rm "$i"; done

如果您试图一次删除大量文件(我今天删除了一个485000+的目录),您可能会遇到以下错误:

/bin/rm: Argument list too long.

问题是,当您键入类似rm-rf*的内容时,*将被替换为每个匹配文件的列表,如“rm-rf file1 file2 file3 file4”等。分配了一个相对较小的内存缓冲区来存储此参数列表,如果该缓冲区已满,shell将不会执行程序。

为了解决这个问题,很多人会使用find命令查找每个文件,并将它们逐一传递给“rm”命令,如下所示:

find . -type f -exec rm -v {} \;

我的问题是我需要删除50万个文件,而且时间太长了。

我偶然发现了一种更快的删除文件的方法——“find”命令内置了“-delete”标志!以下是我最终使用的:

find . -type f -delete

使用这种方法,我以每秒2000个文件的速度删除文件,速度快得多!

您还可以在删除文件名时显示文件名:

find . -type f -print -delete

…甚至显示将删除多少文件,以及删除这些文件所需的时间:

root@devel# ls -1 | wc -l && time find . -type f -delete
100000
real    0m3.660s
user    0m0.036s
sys     0m0.552s

rm命令对可以同时删除的文件有限制。

一种可能性是,您可以根据文件模式多次使用rm命令删除它们,例如:

rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf

也可以通过find命令删除它们:

find . -name "*.pdf" -exec rm {} \;