bash 删除除两个特定目录之外的所有文件/目录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/862388/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Delete all files/directories except two specific directories
提问by phuzion
So, there seems to be a few questions asking about removing files/directories matching certain cases, but I'm looking for the exact opposite: Delete EVERYTHING in a folder that DOESN'T match my provided examples.
因此,似乎有一些问题要求删除与某些情况匹配的文件/目录,但我正在寻找完全相反的内容:删除与我提供的示例不匹配的文件夹中的所有内容。
For example, here is an example directory tree:
例如,这是一个示例目录树:
.
|-- 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
I want to delete everything but the files in test/icecream/cupcake/ and test/mtndew/livewire/. Everything else can go, including the directory structure. So, how can I achieve this? Languages I wouldn't mind this being in: bash or python.
我想删除除 test/icecream/cupcake/ 和 test/mtndew/livewire/ 中的文件以外的所有内容。其他一切都可以去,包括目录结构。那么,我怎样才能做到这一点?我不介意使用的语言:bash 或 python。
采纳答案by lhunath
find's -prunecomes to mind, but it's a pain to get it to work for specific paths (icecream/cupcake/) rather than specific directories (cupcake/).
find我-prune想到了,但是让它为特定路径 ( icecream/cupcake/) 而不是特定目录 ( cupcake/)工作是很痛苦的。
Personally, I'd just use cpioand hard-link (to avoid having to copy them) the files in the directories you want to keep to a new tree and then remove the old one:
就个人而言,我只是使用cpio和硬链接(以避免必须复制它们)您想要保留到新树的目录中的文件,然后删除旧的:
find test -path 'test/icecream/cupcake/*' -o -path 'test/mtndew/livewire/*' | cpio -padluv test-keep
rm -rf test
That'll also keep your existing directory structure for the directories you intend to keep.
这也将保留您打算保留的目录的现有目录结构。
回答by Patrick Webster
This command will leave only the desired files in their original directories:
此命令将仅在其原始目录中保留所需的文件:
find test \( ! -path "test/mtndew/livewire/*" ! -path "test/icecream/cupcake/*" \) -delete
No need for cpio. It works on Ubuntu, Debian 5, and Mac OS X.
不需要cpio。它适用于 Ubuntu、Debian 5 和 Mac OS X。
On Linux, it will report that it cannot delete non-empty directories, which is exactly the desired result. On Mac OS X, it will quietly do the right thing.
在Linux上,它会报告不能删除非空目录,这正是想要的结果。在 Mac OS X 上,它会安静地做正确的事情。
回答by S.Lott
Everything "except" is why we have if-statements; and why os.walk's list of directories is a mutable list.
所有“除了”都是我们有 if 语句的原因;以及为什么 os.walk 的目录列表是可变列表。
for path, dirs, files in os.walk( 'root' ):
if 'coke' in dirs:
dirs.remove('coke')
dirs.remove('pepsi')
回答by lhunath
Move the stuff you want to keep elsewhere, then delete what's left.
把你想保留的东西移到别处,然后删除剩下的。
回答by Jon Cage
You could do something based on Python's os.walk function:
你可以基于Python 的 os.walk 函数做一些事情:
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))
...just add something to ignore the paths you're interested in.
...只需添加一些内容即可忽略您感兴趣的路径。
回答by Marco Cosentino
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
It's a bit tedious to write all the paths to preserve but thi is the only way to use find alone.
编写所有要保留的路径有点乏味,但这是单独使用 find 的唯一方法。
回答by Mr Shark
A oneliner to solve the problem:
一个oneliner来解决问题:
find . |grep -v "test/icecream/cupcake/"| grep -v "test/mtndew/livewire/"|xargs rm -r
找 。|grep -v "测试/冰淇淋/纸杯蛋糕/"| grep -v "test/mtndew/livewire/"|xargs rm -r
Removed since it does not work
已删除,因为它不起作用
this might get you into trouble if have file names with space in them, and it might keep more files then you want if there are other trees that match the patterns.
如果文件名中有空格,这可能会给您带来麻烦,并且如果有其他与模式匹配的树,它可能会保留比您想要的更多的文件。
A somewhat better solution:
一个更好的解决方案:
find . |sed "s/.*/rm '&'/"|grep -v "rm './test/icecream/cupcake/"| grep -v "rm './test/mtndew/livewire/"|sh
Not actually tested, if it breaks you get to keep both parts.
没有实际测试,如果它坏了,你可以保留两个部分。
Edit: As Dennis points its not only two parts that it breaks into :-) corrected the typos in the second example and removed the first
编辑:正如丹尼斯指出的那样,它不仅分为两个部分:-) 更正了第二个示例中的拼写错误并删除了第一个示例
回答by dsm
回答by dsm
It works for me with find using two steps: first delete the files allowed, then their empty directories!
它使用两个步骤查找对我有用:首先删除允许的文件,然后删除它们的空目录!
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
回答by Andrej Panjkov
Like others I have used os.walk and os.path.join to build the list of files to delete, with fnmatch.fnmatch to select files that must be included or excluded:
像其他人一样,我使用 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
If fnmatch isn't enough, you can use the re module to test patterns.
如果 fnmatch 还不够,您可以使用 re 模块来测试模式。
Here I have built the file list before I do anything with it, but you could process the files as they are generated.
在这里,我在对其进行任何操作之前已构建了文件列表,但是您可以在生成文件时对其进行处理。
The try/except block...is there in case my options class instance doesn't have an exclude pattern, or if it causes an exception in fnmatch because it is the wrong type.
try/except 块...是否在我的选项类实例没有排除模式的情况下,或者如果它在 fnmatch 中导致异常,因为它是错误的类型。
A limitation of this method is that it first includesfiles matching a pattern, then excludes. If you need more flexibility than this (include matching pattern a, but not pattern b unless pattern c...) well, then the fragment above isn't up to it. In fact, working through this exercise, you start to see why the find command syntax is the way it is. Seems clunky, but in fact it is exactly the way to do this.
这种方法的一个限制是它首先包含匹配模式的文件,然后排除. 如果您需要比这更多的灵活性(包括匹配模式 a,但不包括模式 b,除非模式 c...),那么上面的片段就不能满足它。事实上,通过这个练习,您开始明白为什么 find 命令的语法是这样的。看起来笨重,但实际上这正是做到这一点的方法。
But if you generate a list, you can filter it according to whatever inclusion/exclusion rules you need.
但是如果您生成一个列表,您可以根据您需要的任何包含/排除规则对其进行过滤。
One nice thing about generating a list is you can check it before you go ahead with the deletion. This is sort of a '--dryrun' option. You can do this interactively in the python interpreter, print the list to see how it looks, apply the next filter, see if it has removed too much or too little and so on.
生成列表的一个好处是您可以在继续删除之前检查它。这是一种“--dryrun”选项。您可以在 python 解释器中以交互方式执行此操作,打印列表以查看它的外观,应用下一个过滤器,查看它是否删除了太多或太少等等。

