我在UNIX的目录下有数百个PDF。PDF的名称确实很长(约60个字符)。
当我尝试使用以下命令一起删除所有PDF时:
rm -f *.pdf
我收到以下错误:
/bin/rm: cannot execute [Argument list too long]
该错误的解决方法是什么?mv
和cp
命令也会发生此错误吗?如果是,该如何解决这些命令?
我在UNIX的目录下有数百个PDF。PDF的名称确实很长(约60个字符)。
当我尝试使用以下命令一起删除所有PDF时:
rm -f *.pdf
我收到以下错误:
/bin/rm: cannot execute [Argument list too long]
该错误的解决方法是什么?mv
和cp
命令也会发生此错误吗?如果是,该如何解决这些命令?
Answers:
发生这种情况的原因是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
xargs
专门将列表分开,并在必要时发出几个命令。
-maxdepth 1
必须是路径后的第一个参数。
-delete
删除所找到文件的标志,即使没有找到,也可以使用-exec
执行rm而不是调用xargs(这是3个进程和一个管道,而不是一个带有-delete
或2个进程-exec
)。
dangerous (broken, exploitable, etc.)
,是相当荒谬的。无疑,使用时要小心xargs
,但事实并非如此eval/evil
。
-exec
调用rm
,进程数将是1 +文件数,尽管与此并发的进程数可能是2(也许可以同时执行rm进程)。使用的进程数量xargs
将大大减少到2 + n,其中n是少于文件数量的一些进程(例如,文件数量/ 10,尽管可能更多取决于路径的长度)。假设find直接进行删除,则-delete
应该使用using 是唯一被调用的过程。
这是命令行参数大小的内核限制。请改用for
循环。
这是一个系统问题,与之相关execve
且ARG_MAX
一直存在。有很多有关文件(见男子execve的,Debian的维基)。
基本上,扩展产生的命令(及其参数)超过了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规范的一部分)。
注意:正如一些评论所指出的那样,这确实较慢,但更易于维护,因为它可以适应更复杂的场景,例如,一个人想做的不只是一项动作。
find
如果您坚持要使用,则可以使用xargs,find
但实际上不要使用xargs,因为它“在读取非NUL分隔的输入时是危险的(损坏,可利用等)”:
find . -maxdepth 1 -name '*.pdf' -delete
使用-maxdepth 1 ... -delete
而不是-exec rm {} +
允许find
自己简单地执行所需的系统调用,而无需使用外部进程,因此速度更快(感谢@chepner comment)。
for
循环。我以前用过find
,但是我一直在寻找操作方法,因为我一直都在忘记选项等。for
似乎更容易想起恕我直言
for f in *; do rm "$f"; done
魅力
find -exec
解决方案似乎是速度远远超过了for
循环。
4.15.0-1019-gcp
准确的说),并限制仍处于2097152.有趣的是,关于Linux的git回购寻找ARG_MAX给人呈现出的结果ARG_MAX是在131702.
find
有一个-delete
动作:
find . -maxdepth 1 -name '*.pdf' -delete
xargs
,按照丹尼斯的答案,按预期工作。
-exec
是删除一堆文件的事实。-exec rm {} +
会做同样的事情,但仍然需要启动至少一个外部进程。-delete
允许find
自己简单地执行所需的系统调用,而无需使用外部包装器。
另一个答案是强制xargs
分批处理命令。例如一次到delete
文件100
,cd
进入目录并运行此命令:
echo *.pdf | xargs -n 100 rm
echo
内置shell的地方起作用。如果最终使用命令echo
,则仍然会遇到程序参数限制。
如果您要一次删除大量文件(我今天删除的目录超过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
sudo find . -type f -delete
删除了约485,000个文件,它对我有用。花了大约20秒。
您可以尝试以下方法:
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脚本并运行它。
所有这些都是出于安全原因。
-rf .. .pdf
-rf
优先于-i
,因此您的第二个版本更好(没有手动检查)。而且对于提示每个文件,基本上对于批量删除没有用。
您可以使用bash数组:
files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
rm -f "${files[@]:I:1000}"
done
这样,它将每步分批擦除1000个文件。
该RM命令有哪些可以删除文件同时的限制。
一种可能性是您可以根据文件模式使用rm命令多次删除它们,例如:
rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf
您也可以通过find命令删除它们:
find . -name "*.pdf" -exec rm {} \;
rm
对要处理的文件数量没有任何限制(但argc
不能大于INT_MAX
)。这是内核对整个参数数组的最大大小的限制(这就是文件名长度很大的原因)。
如果它们是带有空格或特殊字符的文件名,请使用:
find -maxdepth 1 -name '*.pdf' -exec rm "{}" \;
这句话搜索当前目录(-maxdepth 1)中扩展名为pdf(-name'* .pdf')的所有文件,然后删除每个文件(-exec rm“ {}”)。
表达式{}替换文件名,“ {}”将文件名设置为字符串,包括空格或特殊字符。
-exec
是您不调用shell。这里的引号绝对没有用。(它们防止在您在此命令中键入的外壳中的字符串上的任何通配符扩展和令牌拆分,但该字符串{}
不包含任何空格或外壳通配符。)
将表单源目录复制到目标位置时遇到相同问题
源目录中有〜3个lakcs文件
我使用的CP与-r选项,它的工作对我来说
cp -r abc / def /
它将所有文件从abc复制到def,而不会给出参数列表警告太长的时间
如果您想删除30/90天以上(+)或30/90(-)天以下的文件/文件夹,则可以使用以下ex命令
例如:对于90天(不包括90天),在删除90天文件/文件夹后,这意味着91,92 .... 100天
find <path> -type f -mtime +90 -exec rm -rf {} \;
例如:对于您要删除的最新30天文件,请使用以下命令(-)
find <path> -type f -mtime -30 -exec rm -rf {} \;
如果您想将文件保存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 {} \;
我只知道解决这个问题的方法。想法是将您拥有的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)
对不起,我的英语不好。
pdf_format_sucks.docx
它将也将被删除... ;-)在grepping pdf文件时,应使用正确且正确的正则表达式。
still_pdf_format_sucks.docx
会被删除。点.
在".pdf"
正则表达式匹配任何字符。我建议"[.]pdf$"
代替.pdf
。
我几次遇到这个问题。许多解决方案都会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知识的人都可以操纵此代码。
还有一个:
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]
,然后通过将其输出通过管道传递到remove(rm
)命令xargs
,以确保它在命令行中适合足够的文件名,以免失败rm
命令,这是一个shell命令。
将\0
在printf
作为空分隔符至极随后被处理的文件名xargs
的命令,用它(-0
)作为分隔符,所以rm
不会在有空格或在文件名中其他特殊字符失败。
printf
不是内置的Shell,它将受到相同的限制。
您可以创建一个临时文件夹,将要保留的所有文件和子文件夹移到该临时文件夹中,然后删除该旧文件夹,并将该临时文件夹重命名为该旧文件夹,尝试以下示例,直到您有信心将其投入使用:
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
删除*.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提示和技巧以获取更多rsync hack
我发现对于非常大的文件列表(> 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)
比使用xargs更安全的版本,也不是递归的:
ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done
在这里过滤目录是不必要的,因为'rm'不会将其删除,并且为了简单起见可以将其删除,但是为什么要运行肯定会返回错误的东西呢?
find
很好,并且在这里和其他地方都有充分的记录。有关此主题和相关主题的更多信息,请参见例如mywiki.wooledge.org。
使用GNU并行(sudo apt install parallel
)非常容易
它运行多线程命令,其中“ {}”是传递的参数
例如
ls /tmp/myfiles* | parallel 'rm {}'
ls
直接将的输出传递给其他命令是一种危险的反模式-而且通配符的扩展在执行时会产生与ls
原始rm
命令相同的错误,这一事实。
parallel
让一些喜欢避免复杂性的人感到不舒服-如果您在幕后看,那是相当不透明的。请参阅清单.gnu.org / archive / html / bug-parallel / 2015-05 / msg00005.html在Stephane(Unix和Linux StackExchange灰胡子之一)和Ole Tange(Parallel的作者)之间的邮件列表线程。xargs -P
也可以并行化,但是它以更简单,更笨拙的方式实现了运动部件的减少,从而使其行为更容易预测和推理。
要删除前100个文件:
rm -rf'ls | 头-100'