首页 文章

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

提问于
浏览
447

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

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

rm -f *.pdf

我收到以下错误:

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

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

30 回答

  • 642

    如果在删除大量文件时需要保留服务器或系统 responsive ,则每个删除语句之间的 sleep 可能是一个很好的方法 .

    find . -name "*.pdf" -print0 | while read -d $'\0' file
    do
        rm "$file"
        sleep 0.005 # Sleeps for 5ms, tweak as needed
    done
    
  • -1

    rm命令具有可以同时删除的文件的限制 .

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

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

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

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

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

    试试这个:

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

    Warning: 这是一个递归搜索,也会在子目录中找到(和删除)文件 . 只有在您确定不需要确认时,才能将 -f 添加到rm命令 .

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

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

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

    find . -name "*.pdf" -delete
    
  • 0

    tl;博士

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

    问题的根源

    这是一个系统问题,与 execveARG_MAX 常量有关 . 有大量关于此的文档(参见man execvedebian'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) .

    Note: 正如几条评论所指出的那样,这确实更慢但更易于维护,因为它可以适应更复杂的情况,例如:人们想要做的不仅仅是一个动作 .

    解决方案:使用find

    如果你坚持,你可以使用 find 但真的 don't use xargs ,因为它"is dangerous (broken, exploitable, etc.) when reading non-NUL-delimited input":

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

    使用 -maxdepth 1 ... -delete 而不是 -exec rm {} + 允许 find 在不使用外部进程的情况下简单地执行所需的系统调用,因此更快(感谢@chepner comment) .

    参考文献

  • -4

    find 有一个 -delete 动作:

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

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

    echo *.pdf | xargs -n 100 rm

  • 1

    或者您可以尝试:

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

    你可以试试这个:

    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脚本并运行它 .

    所有这些都是出于安全考虑

  • -1

    如果您尝试一次删除大量文件(我今天删除了目录为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
    
  • -2

    你可以使用bash数组:

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

    这样,它将逐步擦除1000个文件 .

  • 16

    您可以使用这个赞扬

    find -name "*.pdf"  -delete
    
  • 3

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

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

    这句话用扩展名pdf(-name'* .pdf')搜索当前目录(-maxdepth 1)中的所有文件,然后删除每一个文件(-exec rm“{}”) .

    表达式{}替换文件的名称,“{}”将文件名设置为字符串,包括空格或特殊字符 .

  • 168

    find . -type f -name '*xxx' -print -delete

  • 0

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

    源目录有文件~3 lakcs

    我使用了 cp with option -r ,这对我有用

    cp -r abc/ def/

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

  • 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知识的人都可以操作这段代码 .

  • -1

    还有一个:

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

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

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

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

  • 2

    我很惊讶这里没有 ulimit 答案 . 每当我遇到这个问题时,我最终都会herehere . 我知道这个解决方案有局限性但是 ulimit -s 65536 似乎经常为我做这个伎俩 .

  • 4

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

    对不起,我的英语不好 .

  • 5

    试试这个如果你想删除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 {} \;
    

    如果你想要文件超过2天giz文件

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

    如果你只想看过去一个月的文件/文件夹 . 例如:

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

    超过30天以上只列出文件/文件夹Ex:

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

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

    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

  • 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黑客

  • 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)
    
  • 6

    当应用程序创建了数百万个无用的日志文件时,我遇到了类似的问题,这些文件填满了所有的inode . 我使用“locate”,将所有文件“定位”到一个文本文件中,然后逐个删除它们 . 花了一段时间,但做了这个工作!

  • 0

    假设输入输入目录名称并输出输出目录名称 . 然后你可以使用简单的循环来复制所有

    for f in input/*
    do
    cp $f output
    done
    
  • -1

    我遇到了同样的问题,一个文件夹充满了日复一日的临时图像,这个命令帮助我清除了文件夹

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

    与其他命令的区别在于mtime参数,该参数仅包含超过X天的文件(在示例中为50天)

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

  • 282

    如果你有 grep 的类似问题,最简单的解决方案是踩一个目录并进行递归搜索 .

    而不是

    grep "something" *
    

    您可以使用:

    cd ..
    grep "something" -R search_in_this_dir/
    

    请注意,它也会递归搜索“search_in_this_dir”目录的子文件夹 .

  • 10

    删除前100个文件:

    rm -rf'ls |头-100'

  • 7

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

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

  • 0

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

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

    例如 .

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

  • -2

    以下选项对于此问题似乎很简单 . 我从其他一些帖子得到了这个信息,但它帮助了我 .

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

    只需运行上面的一个命令即可完成任务 .

相关问题