我在UNIX目录下有几百个PDF。 PDF的名称非常长(大约60个字符)。
当我尝试使用以下命令一起删除所有PDF时:
rm -f *.pdf
我收到以下错误:
/bin/rm: cannot execute [Argument list too long]
此错误的解决方案是什么?
mv
和cp
命令也会出现此错误吗?如果是,如何解决这些命令?
答案 0 :(得分:721)
发生这种情况的原因是因为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
答案 1 :(得分:319)
这是对命令行参数大小的内核限制。改为使用for
循环。
这是与execve
和ARG_MAX
常量相关的系统问题。有大量关于此的文档(请参阅man execve,debian's wiki)。
基本上,扩展会产生超出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 rm "$f"; done
这也是一种可移植的方法,因为glob在shell(part of POSIX spec)中具有强大且一致的行为。
注意:正如一些评论所指出的那样,这确实更慢但更易于维护,因为它可以适应更复杂的场景,例如,其中一个人想做的不仅仅是一个动作。
find
如果您坚持,可以使用find
,但不要使用xargs ,因为“在阅读非NUL时是危险的(破坏,可利用等) - 定界输入“:
find . -maxdepth 1 -name '*.pdf' -delete
使用-maxdepth 1 ... -delete
代替-exec rm {} +
,find
只需执行所需的系统调用,而无需使用外部进程,因此速度更快(感谢@chepner comment)。
答案 2 :(得分:174)
find
有一个-delete
操作:
find . -maxdepth 1 -name '*.pdf' -delete
答案 3 :(得分:19)
另一个答案是强制xargs
批量处理命令。例如,一次delete
个文件100
,cd
进入目录并运行:
echo *.pdf | xargs -n 100 rm
答案 4 :(得分:12)
或者您可以尝试:
find . -name '*.pdf' -exec rm -f {} \;
答案 5 :(得分:9)
你可以试试这个:
for f in *.pdf
do
rm $f
done
编辑: ThiefMaster评论建议我不要向年轻的shell的jedis披露这种危险的做法,所以我会添加一个更“安全”的版本(为了保存某些人有“-rf .pdf”文件时的东西)
echo "# Whooooo" > /tmp/dummy.sh
for f in '*.pdf'
do
echo "rm -i $f" >> /tmp/dummy.sh
done
运行上面的内容后,只需打开你的收藏夹中的/tmp/dummy.sh文件即可。编辑并检查每一行的危险文件名,如果找到则将其注释掉。
然后复制工作目录中的dummy.sh脚本并运行它。
所有这些都是出于安全原因。
答案 6 :(得分:9)
如果您尝试一次删除大量文件(我今天删除了一个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
答案 7 :(得分:5)
您可以使用bash数组:
files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
rm -f "${files[@]:I:1000}"
done
这样每步就会分批擦除1000个文件。
答案 8 :(得分:4)
你可以使用这个推荐
find -name "*.pdf" -delete
答案 9 :(得分:3)
如果它们是带空格或特殊字符的文件名,请使用:
find -maxdepth 1 -name '*.pdf' -exec rm "{}" \;
这句话用扩展名pdf(-name&#39; * .pdf&#39;)搜索当前目录(-maxdepth 1)中的所有文件,然后删除每一个文件(-exec rm&#34; { }&#34;。)
表达式{}替换文件的名称,&#34; {}&#34;将文件名设置为字符串,包括空格或特殊字符。
答案 10 :(得分:3)
rm 命令具有可以同时删除的文件的限制。
您可以使用多次 rm 命令删除它们的一种可能性取决于您的文件模式,例如:
rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf
您也可以通过 find 命令删除它们:
find . -name "*.pdf" -exec rm {} \;
答案 11 :(得分:2)
答案 12 :(得分:2)
我在将表单源目录复制到目标
时遇到了同样的问题源目录有文件~3 lakcs
我使用带选项-r 的 cp,它对我有用
cp -r abc / def /
它会将所有文件从abc复制到def,而不会过长地警告参数列表
答案 13 :(得分:2)
find . -type f -name '*xxx' -print -delete
答案 14 :(得分:1)
我遇到过这个问题几次。许多解决方案将为需要删除的每个文件运行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知识的人都可以操作这段代码。
答案 15 :(得分:1)
还有一个:
cd /path/to/pdf
printf "%s\0" *.[Pp][Dd][Ff] | xargs -0 rm
printf
是一个内置的shell,据我所知,它一直是这样的。现在假设printf
不是shell命令(但是是内置命令),它不会受到“argument list too long ...
”致命错误的影响。
因此我们可以安全地将它与shell {* 1}}之类的shell globbing模式一起使用,然后通过*.[Pp][Dd][Ff]
将其输出移植到remove(rm
)命令,这样可以确保它足够合适命令行中的文件名,以免xargs
命令失败,这是一个shell命令。
rm
中的\0
用作文件名的空分隔符,然后由printf
命令处理,使用它(xargs
)作为分隔符,因此当文件名中有空格或其他特殊字符时,-0
不会失败。
答案 16 :(得分:0)
如果你想同时删除文件和目录,你可以使用类似的方法:
echo /path/* | xargs rm -rf
答案 17 :(得分:0)
此问题标题为cp
,mv
和rm
,但答案大多代表rm
。
仔细阅读命令的手册页!
对于cp
和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" {} +
bash脚本中使用了一个整体工作方式:
#!/bin/bash
folder=( "/path to folder" "/path to anther folder" )
[ "$1" = "--run" ] && exec find "${target[@]}" -type f -name '*.pdf' -exec $0 {} +
for file ;do
printf "Doing something with '%s'.\n" "$file"
done
答案 18 :(得分:0)
又短又可靠的呢?
for i in **/*.pdf; do rm "$i"; done
答案 19 :(得分:0)
当应用程序创建的数百万个无用的日志文件填充了所有索引节点时,我也遇到了类似的问题。我求助于“定位”,将所有文件“定位”到一个文本文件中,然后将它们一一删除。花了一段时间,但完成了工作!
答案 20 :(得分:0)
如果您需要在删除大量文件时保持服务器或系统响应,则每个删除语句之间的sleep
可能是一种很好的方法。
find . -name "*.pdf" -print0 | while read -d $'\0' file
do
rm "$file"
sleep 0.005 # Sleeps for 5ms, tweak as needed
done
答案 21 :(得分: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
答案 22 :(得分:0)
删除目录*.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
删除特定文件可能是最快的解决方案,以防您拥有数百万个文件。它会照顾你得到的错误。
(可选步骤):DRY RUN。检查将删除的内容而不删除。 `
rsync -avhn --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/
。 。
点击rsync tips and tricks了解更多rsync hacks
答案 23 :(得分:0)
试试这个如果你想删除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 {} \;
答案 24 :(得分:0)
我发现对于非常大的文件列表(&gt; 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)
答案 25 :(得分: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)
抱歉我的英语不好。
答案 26 :(得分:-1)
如果您遇到与 grep 类似的问题,最简单的解决方案是退回一个目录并进行递归搜索。
所以而不是
grep "something" *
你可以使用:
cd ..
grep "something" -R search_in_this_dir/
请注意,它也会递归搜索“search_in_this_dir”目录的子文件夹。
答案 27 :(得分:-1)
我对一个日常生长的临时图像的文件夹遇到了同样的问题,这个命令帮我清理了文件夹
find . -name "*.png" -mtime +50 -exec rm {} \;
与其他命令的区别在于mtime参数只接受超过X天的文件(在示例中为50天)
多次使用,减少每天执行的日期范围,我能够删除所有不必要的文件
答案 28 :(得分:-1)
假设输入输入目录名称并输出输出目录名称。 然后你可以使用简单的循环来复制所有
for f in input/*
do
cp $f output
done
答案 29 :(得分:-2)
删除前100个文件:
rm -rf'ls |头-100'
答案 30 :(得分:-2)
使用GNU parallel(sudo apt install parallel
)非常简单
它运行多线程命令,其中'{}'是传递的参数
E.g。
ls /tmp/myfiles* | parallel 'rm {}'
答案 31 :(得分:-2)
比使用xargs更安全的版本,也不是递归的:
ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done
在这里过滤我们的目录有点不必要,因为&#39; rm&#39;无论如何都不会删除它,为了简单起见,它可以删除,但为什么运行肯定会返回错误的东西?
答案 32 :(得分:-4)
以下选项对于此问题似乎很简单。我从其他一些帖子得到了这个信息,但它帮助了我。
for file in /usr/op/data/Software/temp/application/openpages-storage/*; do
cp "$file" /opt/sw/op-storage/
done
只需运行上面的一个命令即可完成任务。