777

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

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

rm -f *.pdf

我收到以下错误:

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

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

4

31 回答 31

1086

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

试试这个:

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

警告:这是一个递归搜索,也会在子目录中查找(并删除)文件。-f仅当您确定不想确认时才使用 rm 命令。

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

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

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

find . -name "*.pdf" -delete
于 2012-07-02T07:44:39.153 回答
503

tl;博士

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

问题的根源

这是一个系统问题,相关execveARG_MAX不变。有很多关于这方面的文档(参见man execvedebian 的 wikiARG_MAX details)。

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

getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic

解决方案:使用for循环

使用BashFAQ/095for上推荐的循环,除了 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 评论)。

参考

于 2013-09-05T23:53:45.553 回答
196

find有一个-delete动作:

find . -maxdepth 1 -name '*.pdf' -delete
于 2012-07-02T22:30:13.847 回答
23

另一个答案是强制xargs批量处理命令。例如一次到delete文件100cd进入目录并运行:

echo *.pdf | xargs -n 100 rm

于 2015-03-04T09:45:56.803 回答
15

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

/bin/rm: Argument list too long.

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

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

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

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

我偶然发现了一种更快的删除文件的方法——“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
于 2018-01-22T09:10:47.490 回答
14

或者您可以尝试:

find . -name '*.pdf' -exec rm -f {} \;
于 2012-07-02T07:47:58.953 回答
13

你可以试试这个:

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

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

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

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

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

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

于 2012-07-02T07:46:09.233 回答
8

您可以使用 bash 数组:

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

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

于 2014-03-18T16:36:01.157 回答
8

我很惊讶这里没有ulimit答案。每次我遇到这个问题时,我都会在这里这里结束。我知道这个解决方案有局限性,但ulimit -s 65536似乎经常为我解决问题。

于 2018-09-02T04:41:59.370 回答
6

你可以使用这个推荐

find -name "*.pdf"  -delete
于 2016-09-08T06:45:31.220 回答
5

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

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

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

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

find . -name "*.pdf" -exec rm {} \;
于 2014-08-29T16:55:20.823 回答
3

还有一个:

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

printf是一个内置的shell,据我所知,它一直都是这样。现在鉴于这printf不是一个 shell 命令(而是一个内置命令),它不会受到 " argument list too long ..." 致命错误的影响。

所以我们可以安全地将它与 shell *.[Pp][Dd][Ff]globbing模式(例如命令。rmxargsrm

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

于 2012-07-02T22:27:13.537 回答
3

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

源目录有文件〜3 lakcs

我将cp 与选项 -r一起使用,它对我有用

cp -r abc/def/

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

于 2014-03-11T07:40:35.023 回答
3

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

find -name "*.pdf"  -delete

仅适用于当前目录中的文件:

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

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

于 2016-06-09T15:30:35.730 回答
3

也试试这个如果你想删除超过 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 {} \;
于 2017-10-06T08:43:59.863 回答
3

参数列表太长

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

Un*x 命令

仔细阅读命令的手册页!

对于cpand mv,有一个-t开关,对于target

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" ] ;then
    exec find "${folder[@]}" -type f -name '*.pdf' -exec $0 --run {} +
    exit 0;
fi

shift

for file ;do
    printf "Doing something with '%s'.\n" "$file"
done
于 2020-11-30T12:02:21.297 回答
1

我在一个充满临时图像的文件夹中遇到了同样的问题,该文件夹每天都在增长,这个命令帮助我清除了该文件夹

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

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

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

于 2016-03-23T11:35:47.737 回答
1

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

mkdir empty_dir        # Create temp empty dir

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

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


(可选步骤):试运行。检查哪些内容将被删除而不删除。`

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

. . .

单击rsync 提示和技巧以获取更多 rsync hack

于 2018-01-15T20:32:41.203 回答
1

更短更可靠的呢?

for i in **/*.pdf; do rm "$i"; done
于 2020-06-23T22:05:19.510 回答
1

如果你想同时删除文件和目录,你可以使用类似的东西:

echo /path/* | xargs rm -rf
于 2021-03-28T14:47:22.550 回答
1

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

ulimit -S -s unlimited

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

于 2022-02-10T06:14:25.227 回答
0

我只知道解决这个问题的方法。这个想法是将您拥有的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)

对不起,我的英语不好。

于 2013-11-28T02:46:14.303 回答
0

我几次遇到这个问题。许多解决方案将为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 了解最少甚至没有的人都可以操作此代码。

于 2015-02-04T17:13:54.087 回答
0

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

(这节省了我几个小时)

# delete files
import os as os
import glob
import 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 command
def 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)
于 2017-07-25T02:06:19.223 回答
0

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

mkdir testit
cd testit
mkdir big_folder tmp_folder
touch big_folder/file1.pdf
touch big_folder/file2.pdf
mv big_folder/file1,pdf tmp_folder/
rm -r big_folder
mv tmp_folder big_folder

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

于 2018-04-19T00:51:57.960 回答
0

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

于 2018-07-16T05:39:31.607 回答
0

我解决了for

macOS继续zsh

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

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

比使用 xargs 更安全的版本,也不是递归的: ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done

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

于 2016-05-11T09:29:15.577 回答
-2

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

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

例如

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

于 2017-08-24T21:54:36.463 回答
-2

要删除前 100 个文件:

rm -rf 'ls | 头 -100'

于 2018-01-30T10:20:58.230 回答
-5

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

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

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

于 2017-01-31T23:41:26.970 回答