我在 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
?如果是,如何解决这些命令?
发生这种情况的原因是因为 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
这是对命令行参数大小的内核限制。请改用for
循环。
这是一个系统问题,相关execve
且ARG_MAX
不变。有很多关于这方面的文档(参见man execve、debian 的 wiki、ARG_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 评论)。
find
有一个-delete
动作:
find . -maxdepth 1 -name '*.pdf' -delete
另一个答案是强制xargs
批量处理命令。例如一次到delete
文件100
,cd
进入目录并运行:
echo *.pdf | xargs -n 100 rm
如果您尝试一次删除大量文件(我今天删除了一个有 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
或者您可以尝试:
find . -name '*.pdf' -exec rm -f {} \;
你可以试试这个:
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
您的工作目录中并运行它。
所有这些都是出于安全原因。
您可以使用 bash 数组:
files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
rm -f "${files[@]:I:1000}"
done
这样,它将每步擦除 1000 个文件。
你可以使用这个推荐
find -name "*.pdf" -delete
rm命令对可以同时删除的文件有限制。
一种可能是您可以根据文件模式多次使用rm命令删除它们,例如:
rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf
您也可以通过find命令删除它们:
find . -name "*.pdf" -exec rm {} \;
还有一个:
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模式(例如命令。rm
xargs
rm
\0
inprintf
用作文件名的空分隔符,然后由命令处理,xargs
使用它 ( -0
) 作为分隔符,因此rm
当文件名中有空格或其他特殊字符时不会失败。
我在将表单源目录复制到目标时遇到了同样的问题
源目录有文件〜3 lakcs
我将cp 与选项 -r一起使用,它对我有用
cp -r abc/def/
它会将所有文件从 abc 复制到 def 而不给出参数列表太长的警告
如果它们是带有空格或特殊字符的文件名,请使用:
find -name "*.pdf" -delete
仅适用于当前目录中的文件:
find -maxdepth 1 -name '*.pdf' -delete
这句话搜索当前目录(-maxdepth 1)中所有扩展名为pdf(-name '*.pdf')的文件,然后,删除。
也试试这个如果你想删除超过 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 {} \;
作为这个问题的标题cp
,mv
和rm
,但答案主要代表rm
。
仔细阅读命令的手册页!
对于cp
and 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" )
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
我在一个充满临时图像的文件夹中遇到了同样的问题,该文件夹每天都在增长,这个命令帮助我清除了该文件夹
find . -name "*.png" -mtime +50 -exec rm {} \;
与其他命令的不同之处在于 mtime 参数将只接受早于 X 天的文件(在示例中为 50 天)
多次使用,减少每次执行的日期范围,我能够删除所有不必要的文件
删除*.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
更短更可靠的呢?
for i in **/*.pdf; do rm "$i"; done
如果你想同时删除文件和目录,你可以使用类似的东西:
echo /path/* | xargs rm -rf
对于没有时间的人。 在终端上运行以下命令。
ulimit -S -s unlimited
然后执行 cp/mv/rm 操作。
我只知道解决这个问题的方法。这个想法是将您拥有的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)
对不起,我的英语不好。
我几次遇到这个问题。许多解决方案将为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 了解最少甚至没有的人都可以操作此代码。
我发现对于非常大的文件列表(> 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)
您可以创建一个临时文件夹,将要保留的所有文件和子文件夹移动到临时文件夹中,然后删除旧文件夹并将临时文件夹重命名为旧文件夹尝试此示例,直到您有信心执行此操作:
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
当一个应用程序创建了数百万个无用的日志文件并填满了所有 inode 时,我遇到了类似的问题。我求助于“定位”,将所有文件“定位”到一个文本文件中,然后一一删除。花了一段时间,但完成了工作!
for
macOS
继续zsh
jpg
文件。在mv
一行命令内。for i in $(find ~/old -type f -name "*.jpg"); do mv $i ~/new; done
比使用 xargs 更安全的版本,也不是递归的:
ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done
在这里过滤我们的目录有点不必要,因为'rm'无论如何都不会删除它,并且为了简单起见可以将其删除,但是为什么要运行肯定会返回错误的东西呢?
使用 GNU 并行 ( sudo apt install parallel
) 非常简单
它运行多线程命令,其中“{}”是传递的参数
例如
ls /tmp/myfiles* | parallel 'rm {}'
要删除前 100 个文件:
rm -rf 'ls | 头 -100'
对于这个问题,下面的选项似乎很简单。我从其他线程中获得了此信息,但它对我有所帮助。
for file in /usr/op/data/Software/temp/application/openpages-storage/*; do
cp "$file" /opt/sw/op-storage/
done
只需运行上述一个命令,它就会完成任务。