【问题标题】:Delete all files/directories except two specific directories删除除两个特定目录外的所有文件/目录
【发布时间】:2010-10-26 03:09:47
【问题描述】:

因此,似乎有几个问题询问删除与某些情况匹配的文件/目录,但我正在寻找完全相反的内容:删除与我提供的示例不匹配的文件夹中的所有内容。

例如,这里是一个示例目录树:

.
|-- coke
|   |-- diet
|   |-- regular
|   `-- vanilla
|-- icecream
|   |-- chocolate
|   |-- cookiedough
|   |-- cupcake
|   |   |-- file1.txt
|   |   |-- file2.txt
|   |   |-- file3.txt
|   |   |-- file4.txt
|   |   `-- file5.txt
|   `-- vanilla
|-- lol.txt
|-- mtndew
|   |-- classic
|   |-- codered
|   |-- livewire
|   |   |-- file1.txt
|   |   |-- file2.txt
|   |   |-- file3.txt
|   |   |-- file4.txt
|   |   `-- file5.txt
|   `-- throwback
`-- pepsi
    |-- blue
    |-- classic
    |-- diet
    `-- throwback

我想删除除 test/icecream/cupcake/ 和 test/mtndew/livewire/ 中的文件以外的所有内容。其他一切都可以,包括目录结构。那么,我该如何实现呢?我不介意使用的语言:bash 或 python。

【问题讨论】:

    标签: python linux bash


    【解决方案1】:
    find /path/to/test/ -depth -mindepth 1 \
    ! -path "/path/to/test/icecream/cupcake/*" \
    ! -path "/path/to/test/icecream/cupcake" \
    ! -path "/path/to/test/icecream" \
    ! -path "/path/to/test/mtndew/livewire/*" \
    ! -path "/path/to/test/mtndew/livewire" \
    ! -path "/path/to/test/mtndew"
     -delete -print
    

    编写所有要保存的路径有点繁琐,但这是单独使用 find 的唯一方法。

    【讨论】:

      【解决方案2】:

      解决问题的oneliner:

      找到 . |grep -v "测试/冰淇淋/纸杯蛋糕/"| grep -v "test/mtndew/livewire/"|xargs rm -r

      由于它不起作用而被删除

      如果文件名中包含空格,这可能会给您带来麻烦,并且如果存在与模式匹配的其他树,它可能会保留比您想要的更多的文件。

      一个更好的解决方案:

      find . |sed "s/.*/rm '&'/"|grep -v "rm './test/icecream/cupcake/"| grep -v "rm './test/mtndew/livewire/"|sh
      

      没有经过实际测试,如果它坏了,你可以保留这两个部分。

      编辑:正如丹尼斯指出的那样,它不仅分为两个部分:-) 更正了第二个示例中的拼写错误并删除了第一个

      【讨论】:

      • 在您的第一个示例中,它将 rm -r test/icecream 包括纸杯蛋糕(例如)。所以,即使你已经 grep -v 纸杯蛋糕,它们仍然会被“吃掉”。第二个例子有几个错别字和不平衡的单引号。 sed 后面应该有一个空格,零应该是 & 符号。
      • 路径周围的单引号仍然不平衡。例如,应该是“rm'./test/icecream/cupcake/'”
      【解决方案3】:

      此命令将仅将所需文件保留在其原始目录中:

      find test \( ! -path "test/mtndew/livewire/*" ! -path "test/icecream/cupcake/*" \) -delete
      

      不需要cpio。它适用于 Ubuntu、Debian 5 和 Mac OS X。

      在Linux上,它会报告它不能删除非空目录,这正是想要的结果。在 Mac OS X 上,它会悄悄地做正确的事。

      【讨论】:

      • 这会找到 test 并将其删除,从而删除您要保存的目录。
      • 这会找到 test 并且不会删除它,因为它是非空的。是否有任何现代版本的 Linux 或 Unix 无法使用此命令?
      • 抱歉,我在系统上设置测试时出错。您的示例对我来说是正确的。
      • 虽然这不是最初的问题,但有些人可能会觉得这很有用:您可以保留整个目录结构,并且只删除未使用test 排除的文件,方法是在-type f 之前添加-type f 标志@987654324 @.
      【解决方案4】:

      和其他人一样,我使用 os.walk 和 os.path.join 构建要删除的文件列表,使用 fnmatch.fnmatch 选择必须包含或排除的文件:

      #-------------------------------#
      # make list of files to display #
      #-------------------------------#
      displayList = []
      for imageDir in args :
          for root,dirs,files in  os.walk(imageDir) :
              for filename in files :
                  pathname = os.path.join( root, filename ) 
                  if fnmatch.fnmatch( pathname, options.includePattern ) :
                      displayList.append( pathname )
      
      
      #----# now filter out excluded patterns #----#
      try :
          if len(options.excludePattern) > 0 :
              for pattern in options.excludePattern :
                  displayList = [pathname for pathname in displayList if not fnmatch.fnmatch( pathname, pattern ) ]
      except ( AttributeError, TypeError ) :
          pass
      

      如果 fnmatch 不够,可以使用 re 模块来测试模式。

      在这里,我在对其进行任何操作之前已经构建了文件列表,但是您可以在生成文件时对其进行处理。

      try/except 块......如果我的选项类实例没有排除模式,或者它在 fnmatch 中导致异常,因为它是错误的类型。

      此方法的一个限制是它首先包含 匹配模式的文件,然后排除。如果您需要比这更多的灵活性(包括匹配模式 a,但不包括模式 b,除非模式 c ...),那么上面的片段不适合它。事实上,通过本练习,您开始了解 find 命令语法为何如此。看起来很笨拙,但实际上这正是这样做的方式。

      但是,如果您生成一个列表,您可以根据您需要的任何包含/排除规则对其进行过滤。

      生成列表的一个好处是您可以在继续删除之前检查它。这是一种“--dryrun”选项。您可以在 python 解释器中以交互方式执行此操作,打印列表以查看其外观,应用下一个过滤器,查看它是否删除了太多或太少等等。

      【讨论】:

        【解决方案5】:

        它适用于我的 find 使用两个步骤:首先删除允许的文件,然后删除它们的空目录!

        find -x -E ~/Desktop/test -not \( -type d -regex '.*/(cupcake|livewire)/*.*' -prune \) -print0 | xargs -0 ls -1 -dG 
        
        # delete the files first
        
        # Mac OS X 10.4 
        find -x -E ~/Desktop/test -not \( -type d -regex '.*/(cupcake|livewire)/*.*' -prune \) -type f -exec /bin/rm -fv '{}' \; 
        
        # Mac OS X 10.5 
        find -x -E ~/Desktop/test -not \( -type d -regex '.*/(cupcake|livewire)/*.*' -prune \) -type f -exec /bin/rm -fv '{}' + 
        
        # delete empty directories 
        find -x ~/Desktop/test -type d -empty -delete 
        

        【讨论】:

        • 在 ubuntu 上,find 没有 -x -E,因此等价于:find ~/Desktop/test -xdev -regextype posix-extended-not ( -type d -regex '. */(cupcake|livewire)/*.*' -prune ) -print0 | xargs -0 ls -1 -dG
        • 此外,在某些情况下,可能有必要保护您想要保留的空目录,在您的答案的最后一步中使用 find -empty 命令中的相同正则表达式。您可能想澄清一下,您的第一个命令是对概念验证的测试,否则不属于您演示的两个步骤。
        【解决方案6】:

        把你想保留的东西移到别处,然后删除剩下的。

        【讨论】:

          【解决方案7】:

          想到了find-prune,但让它适用于特定路径 (icecream/cupcake/) 而不是特定目录 (cupcake/) 会很痛苦。

          就我个人而言,我只是使用cpio 并硬链接(以避免复制它们)您想要保留到新树的目录中的文件,然后删除旧的:

          find test -path 'test/icecream/cupcake/*' -o -path 'test/mtndew/livewire/*' | cpio -padluv test-keep
          rm -rf test
          

          这也将为您打算保留的目录保留现有的目录结构。

          【讨论】:

            【解决方案8】:

            所有“除了”都是我们有 if 语句的原因;以及为什么 os.walk 的目录列表是可变列表。

            for path, dirs, files in os.walk( 'root' ):
                if 'coke' in dirs:
                    dirs.remove('coke')
                    dirs.remove('pepsi')
            

            【讨论】:

              【解决方案9】:

              你可以根据Python's os.walk function做一些事情:

              import os
              for root, dirs, files in os.walk(top, topdown=False):
                  for name in files:
                      os.remove(os.path.join(root, name))
                  for name in dirs:
                      os.rmdir(os.path.join(root, name))
              

              ...只需添加一些内容以忽略您感兴趣的路径。

              【讨论】:

                【解决方案10】:

                使用find

                您的命令将类似于:

                find $directory \( -prune 'some pattern' \) -delete
                

                【讨论】:

                • 试过这个,它说:find /home/phuzion/test/ \( -prune 'icecream/cupcake/' \) -delete find: 路径必须在表达式之前
                • 来自 find 的手册页:“因为 -delete 意味着 -depth,所以不能同时使用 -prune 和 -delete。”
                • 正确的语法更像是“find $directory -path ./pepsi/diet -prune -o -exec some-command '{}' \;”无论如何要消除该错误消息。
                猜你喜欢
                • 2016-01-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-07
                • 2021-06-11
                • 2015-11-05
                • 2018-01-05
                相关资源
                最近更新 更多