rm、cp、mv命令的参数列表太长错误

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

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

rm -f *.pdf

我得到以下错误:

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

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

794940 次浏览

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

试试这个:

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

警告:这是一个递归搜索,也会在子目录中查找(和删除)文件。仅当您确定不需要确认时,才将-f添加到rm命令。

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

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

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

find . -name "*.pdf" -delete

你可以试试这个:

for f in *.pdfdorm "$f"done

编辑:ThiefMaster建议我不要向年轻的shell的jedis透露这种危险的做法,所以我会添加一个更“安全”的版本(为了在有人拥有“-rf… pdf”文件时保存东西)

echo "# Whooooo" > /tmp/dummy.shfor f in '*.pdf'doecho "rm -i \"$f\""done >> /tmp/dummy.sh

运行上述操作后,只需在您最喜欢的编辑器中打开/tmp/dummy.sh文件并检查每一行是否有危险的文件名,如果找到则将其注释掉。

然后将dummy.sh脚本复制到您的工作目录中并运行它。

所有这些都是出于安全原因。

或者你可以尝试:

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

还有一个:

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

printf是一个shell内置命令,据我所知它一直是这样的。现在假设printf不是shell命令(而是内置命令),它不会出现“argument list too long ...”致命错误。

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

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

find有一个-delete的动作:

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

tl; dr

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

问题的根源

这是一个系统问题,与execveARG_MAX常量有关。关于这一点有很多留档(参见男子执行debian的wikiARG_MAX细节)。

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

getconf ARG_MAX# 2097152 # on 3.5.0-40-generic

解决方案:使用for循环

使用for循环,因为它在BashFAQ/095上推荐,除了RAM/内存空间之外没有限制:

试运行以确定它会删除您期望的内容:

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

并执行它:

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

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

备注:正如一些评论所指出的,这确实较慢,但更易于维护,因为它可以适应更复杂的场景,e. g.其中人们想要做的不仅仅是一个操作。

解决方案:使用find

如果你坚持,你可以使用find,但实际上不要使用xargs作为"读取非NUL分隔的输入时是危险的(损坏、可利用等)"

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

使用-maxdepth 1 ... -delete而不是-exec rm {} +允许find简单地执行所需的系统调用本身,而无需使用外部进程,因此更快(感谢@陈志立)。

参考文献

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

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

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

split -l 600 list.txt

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

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

对不起我的英语不好。

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

源代码目录有文件~3 lakcs

我用了带有选项-r的cp,它对我有用

cp-r abc/def/

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

你可以使用bash数组:

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

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

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

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

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

您也可以通过找到命令删除它们:

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

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

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

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

import osfiledir = '/tmp/' #The directory you wish to run rm onfilelist = (os.listdir(filedir)) #gets listing of all files in the specified dirnewlist = [] #Makes a blank list named newlistfor i in filelist:if str((i)[:4]) not in newlist: #This makes sure that the elements are unique for newlistnewlist.append((i)[:4]) #This takes only the first 4 charcters of the folder/filename and appends it to newlistfor i in newlist:if 'tmp' in i:  #If statment to look for tmp in the filename/dirnameprint ('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 countos.system('rm -rf '+str(filedir)+str(i)+'*') #Actual shell commandprint ('DONE')

这对我来说工作得很好。我能够在大约15分钟内清除文件夹中的200万临时文件。我注释了一小部分代码中的tar,因此任何对python知识很少甚至没有了解的人都可以操作此代码。

另一个答案是强制xargs批量处理命令。例如,要delete一次将文件100cd放入目录并运行以下命令:

echo *.pdf | xargs -n 100 rm

我有同样的问题与一个文件夹充满了临时图像这是日益增长这一命令帮助我清除文件夹

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

与其他命令的区别在于mtime参数,它只接受超过X天的文件(在示例中为50天)

多次使用,每次执行减少一天的范围,我能够删除所有不必要的文件

比使用xargs更安全的版本,也不是递归的:ls-p|grep-v '/$' | grep'\. pdf$'|读取文件时;做rm"$file";完成

在这里过滤我们的目录有点不必要,因为'rm'无论如何都不会删除它,并且为了简单起见可以将其删除,但是为什么要运行肯定会返回错误的东西呢?

如果它们是带空格或特殊字符的文件名,请使用:

find -name "*.pdf"  -delete

仅对于当前目录中的文件:

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

这句话用扩展名pdf(-name'*. pdf')搜索当前目录(-max深度1)中的所有文件,然后删除。

你可以用这个表扬

find -name "*.pdf"  -delete

下面的选项对这个问题似乎很简单。我从其他线程得到了这个信息,但它帮助了我。

for file in /usr/op/data/Software/temp/application/openpages-storage/*; docp "$file" /opt/sw/op-storage/done

只需运行上面的一个命令,它就会完成任务。

我发现对于非常大的文件列表(>1e6),这些答案太慢了。这是一个在python中使用并行处理的解决方案。我知道,我知道,这不是linux…但这里没有其他东西有效。

(这节省了我的时间)

# delete filesimport os as osimport globimport multiprocessing as mp
directory = r'your/directory'os.chdir(directory)

files_names = [i for i in glob.glob('*.{}'.format('pdf'))]
# report errors from pool
def callback_error(result):print('error', result)
# delete file using system commanddef delete_files(file_name):os.system('rm -rf ' + file_name)
pool = mp.Pool(12)# or use pool = mp.Pool(mp.cpu_count())

if __name__ == '__main__':for file_name in files_names:print(file_name)pool.apply_async(delete_files,[file_name], error_callback=callback_error)

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

它多线程运行命令,其中{}是传递的参数

例如。

ls /tmp/myfiles* | parallel 'rm {}'

如果您想删除超过30/90天(+)或低于30/90天(-)天的文件/文件夹,那么您可以使用以下ex命令

例如:90天不包括上述90天文件/文件夹删除后,这意味着91,92……100天

find <path> -type f -mtime +90 -exec rm -rf {} \;

例如:对于您要删除的最新30天文件,请使用以下命令(-)

find <path> -type f -mtime -30 -exec rm -rf {} \;

如果您想giz文件超过2天的文件

find <path> -type f -mtime +2 -exec gzip {} \;

如果您只想查看过去一个月的文件/文件夹。例如:

find <path> -type f -mtime -30 -exec ls -lrt {} \;

30天以上才列出文件/文件夹例如:

find <path> -type f -mtime +30 -exec ls -lrt {} \;
find /opt/app/logs -type f -mtime +30 -exec ls -lrt {} \;

删除目录/path/to/dir_with_pdf_files/中的所有*.pdf

mkdir empty_dir        # Create temp empty dir
rsync -avh --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/

如果您有数百万个文件,使用通配符通过rsync删除特定文件可能是最快的解决方案。它会处理您遇到的错误。


(可选步骤):DRY RUN。检查将删除的内容而不删除。

rsync -avhn --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/

。..

单击rsync提示和技巧获取更多rsync黑客

如果您尝试一次删除大量文件(我今天删除了485,000多个目录),您可能会遇到此错误:

/bin/rm: Argument list too long.

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

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

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

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

我偶然发现了一种更快的删除文件的方法-“查找”命令内置了一个“删除”标志!这是我最终使用的:

find . -type f -delete

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

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

find . -type f -print -delete

…甚至显示将删除多少文件,然后计算删除它们所需的时间:

root@devel# ls -1 | wc -l && time find . -type f -delete100000real    0m3.660suser    0m0.036ssys     0m0.552s

删除前100个文件:

rm-rf'ls|head-100'

您可以创建临时文件夹,将所有要保留的文件和子文件夹移动到临时文件夹中,然后删除旧文件夹并将临时文件夹重命名为旧文件夹尝试此示例,直到您有信心实时执行此操作:

mkdir testitcd testitmkdir big_folder tmp_foldertouch big_folder/file1.pdftouch big_folder/file2.pdfmv big_folder/file1,pdf tmp_folder/rm -r big_foldermv tmp_folder big_folder

rm -r big_folder将删除big_folder中的所有文件,无论有多少。您只需非常小心,您首先拥有要保留的所有文件/文件夹,在这种情况下是file1.pdf

我也遇到过类似的问题,当一个应用程序创建了数百万个无用的日志文件,填满了所有的inode时。我求助于“定位”,将所有“定位”的文件d放入一个文本文件中,然后一个接一个地删除它们。花了一段时间,但完成了工作!

我很惊讶这里没有ulimit的答案。每次我遇到这个问题,我最终都会得到这里这里。我知道这个解决方案有局限性,但ulimit -s 65536似乎经常对我起作用。

短一点靠谱一点的呢

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

论点列表太长

作为这个问题的标题cpmvrm,但答案主要代表rm

un*x命令

仔细阅读命令手册页!

对于cpmv,有一个-t开关,对于目标

find . -type f -name '*.pdf' -exec cp -ait "/path to target" {} +

find . -type f -name '*.pdf' -exec mv -t "/path to target" {} +

脚本方式

脚本中使用了一个整体工作流程:

#!/bin/bash
folder=( "/path to folder" "/path to anther folder" )
if [ "$1" != "--run" ] ;thenexec find "${folder[@]}" -type f -name '*.pdf' -exec $0 --run {} +exit 0;fi
shift
for file ;doprintf "Doing something with '%s'.\n" "$file"done

如果您想删除文件和目录,您可以使用以下方式:

echo /path/* | xargs rm -rf

我用for解决了

我在macOSzsh

我只移动了数千个jpg文件。在一行命令中的mv内。

确保您尝试移动的文件名称中没有空格或特殊字符
for i in $(find ~/old -type f -name "*.jpg"); do mv $i ~/new; done

对于那些没有时间的人来说。在终端上运行以下命令。

ulimit -S -s unlimited

然后执行cp/mv/rm操作。