给定以下文件:
data/A/a.txt
data/B/b.pdf
...
date/P/whatever.log
...
data/Z/z.jpg
我想删除data/A/
, data/B/
, ...,data/Z/
目录中的所有文件除了位于文件中列出的目录之一下的那些文件data/dont_clean.txt
。例如,如果我们已data/P
列出,data/dont_clean.txt
则不应在 下触及任何内容data/P/
,等等。
就像是:
find data/ -mindepth 2 -maxdepth 2 -type f -not -path {listed in data/dont_clean} -delete
当然这不是一个有效的命令。
我也尝试过的变体
find data/ -mindepth 2 -maxdepth 2 -type f -exec grep data/dont_clean.txt '{}' \;
但我只创建了一个无效的命令,或者我不知道为什么我得到了我所做的输出。
我在 Ubuntu 12.10 上使用 bash
答案1
这是我仅粗略测试的代码,但可能会为您提供一种采用的方法。假设您有一个文件,ignore.txt
如下所示:
1/
2/
样本数据
我有示例目录,其中包含如下文件:
$ mkdir -p dirs/{1..5}
$ touch dirs/{1..5}/afile
结果是这样的:
$ tree dirs/
dirs/
|-- 1
| `-- afile
|-- 2
| `-- afile
|-- 3
| `-- afile
|-- 4
| `-- afile
`-- 5
`-- afile
运行示例
现在,如果我们针对这棵树运行此命令:
$ find dirs/ -type f -print0 | fgrep -zFvf ./ignore.txt
dirs/5/afiledirs/4/afiledirs/3/afile
我们可以看到,我们只取回未在 中列出的目录中的文件ignore.txt
。
所以我们可以rm
在末尾添加一个来删除非排除的文件。
$ find dirs/ -type f -print0 | fgrep -zFvf ./ignore.txt | xargs -0 rm -f
检查我们可以看到它有效:
$ tree dirs/
dirs/
|-- 1
| `-- afile
|-- 2
| `-- afile
|-- 3
|-- 4
`-- 5
需要解决的问题
这种方法的一个大问题是文件中的字符串ignore.txt
可能与目录结构的其他部分匹配。因此,需要注意确保该文件中的字符串按照您期望的方式是唯一的。
可以在绳子周围放置一些阻挡物,以便将它们固定在绳子的开头或末端以保护它们。
细节
上述命令执行以下操作:
- 查找目录下的所有文件
dirs
igonre.txt
过滤掉文件中存在的目录下的所有文件- 将过滤器列表传递
xargs
给rm -f
命令
答案2
听起来像是该命令的一个例子comm
。
list of files to not delete in "keeper"
ls >current
comm -23 current ../keeper | more
检查它是否是正确的列表
comm -23 current ../keeper | xargs rm
答案3
xargs
和find
组合
演示:
我的文件 :
[root@mail tmp]# find data/ -type f
data/A/d.txt
data/A/b.txt
data/A/a.txt
data/A/c.txt
data/B/e.txt
data/B/g.txt
data/B/f.txt
data/B/i.txt
排除列表
[root@mail tmp]# cat exclude
data/A/a.txt
data/B/e.txt
使用 xargs 查找
[root@mail tmp]# find data/ -type f $( xargs -I{} echo -n " -not -path {} " < exclude )
data/A/d.txt
data/A/b.txt
data/A/c.txt
data/B/g.txt
data/B/f.txt
data/B/i.txt
看起来输出正常,让删除,但在此之前确保以下命令的输出正常,然后您可以删除倒数第二个echo
命令。
[root@mail tmp]# find data/ -type f $( xargs -I{} echo -n " -not -path {} " < exclude ) | xargs -n1 echo rm -rf
rm -rf data/A/d.txt
rm -rf data/A/b.txt
rm -rf data/A/c.txt
rm -rf data/B/g.txt
rm -rf data/B/f.txt
rm -rf data/B/i.txt
答案4
您可以分两步完成:标记(使它们与众不同),然后删除不受保护的内容。
如果所有这些文件都来自同一用户,则您可以使用该列表将所有权或组更改为另一个用户。然后使用 find 删除其余部分,然后将用户更改回来。如果所有文件都具有相同的读取权限(这样您就知道如何切换回来),您可以例如删除读取权限(以标记它们),因为它比更改用户容易得多(不需要 root 权限):
while read file; do chmod u-w -R "$file"; done < "data/dont_clean.txt"
find data/ -mindepth 2 -maxdepth 2 -type f -writable -delete
while read file; do chmod u+w -R "$file"; done < "data/dont_clean.txt"
编辑(添加递归)以保护整个目录。从读取权限更改为写入权限,以避免 chmod 递归问题(它无法读取刚刚更改的目录)。