我正在尝试修改脚本中的以下命令,以根据年龄删除目录。
示例目录如下:
/a/b/c/2011/11/11
/a/b/c/2011/11/11/12-ACD-1234
/a/b/c/2011/11/14
当前不准确的尝试如下:
find /a/b -type d -mindepth 2 -depth ! -name '*ACD*' -mtime +180 -exec rm -rf {} +
虽然此脚本不会删除包含“ACD”的目录,但会删除父目录。我尝试过 -prune 组合和其他技巧,但无法获得所需的结果。
有没有办法完善此 find 命令以保留符合特定条件的子目录?在此示例中,必须保留父目录 /a/b/c/2011 和 /a/b/c/2011/11,以免递归删除子目录。
如果可能的话,我希望只使用 find 命令来执行此操作。
答案1
主要问题是 find 会为您提供一个漂亮的目录列表作为输出,但您需要一种方法来单独评估每个目录,以确定它们是否*ACD*
在子目录中有位置。而且管道命令似乎不能很好地(或根本不能?)用作 find 的参数-exec
。
因此,一种方法是创建自己的-exec
可以调用的命令脚本,如果其参数不包含子目录,则返回 0 *ACD*
,否则返回 1。这似乎对我有用:
#!/bin/sh
# script: /path/to/hasnoACD
list=`find $1 -name '*ACD*'`
[ "x$list" = "x" ] && exit 0 || exit 1
然后您所需的查找命令只需使用-exec
两次:
find /a/b -type d -mindepth 2 -depth ! -name '*ACD*' -mtime +180 -exec /path/to/hasnoACD {} \; -exec rm -rf {} +
-exec /path/to/hasnoACD {} \;
仅对您想要的情况才会评估为真。
另一种选择:我最初采用与 @icyrock-com 类似的方法,最终使用 find 命令通过管道传输到 while 循环,该循环处理目录删除。'while' 语法取决于您的 shell,您需要一种方法来区分包含某些子目录的目录,*ACD*
就像我们上面使用脚本所做的那样hasnoACD
,但在 FreeBSD 上的 bash 中,以下方法似乎有效:
find /a/b -type d -mindepth 2 -depth ! -name '*ACD*' -mtime +180 | while read mydir ; do find $mydir -name '*ACD*' | xargs false && rm -rf $mydir ; done
请注意 while 循环中的 find —— 仅当 find 未返回任何内容(无*ACD*
子目录)时,xargs 才会返回 true,从而rm -rf $mydir
执行。xargs 的这种行为在我的 FreeBSD 机器上有效,但在 Linux 或 Solaris 上,行为有所不同,因此需要进行其他测试。
正如@icyrock-com 所建议的,您可能希望执行 amv
而不是 a rm
,以确保安全。
答案2
不确定您是否可以find
仅使用此功能,但您可以尝试这里有一个测试脚本 - 在 /tmp 或安全的地方尝试此脚本:
# Prepare
rm -rf a
mkdir -p a/b/c
for a in c d; do
for i in 2010 2011; do
for j in 05 11; do
mkdir -p a/b/$a/$i/$j/will-delete
if [ $j != 05 ]; then
mkdir -p a/b/$a/$i/$j/will-ACD-leave
fi
done
done
done
echo Created
# List
echo ----- Listing
find a
# Remove
echo ----- Removing
find a/b -depth -type d ! -name "*ACD*"|while read l; do
num_entries=`ls -a "$l"|wc -l`
if [ $num_entries -eq 2 ]; then
echo Removing $l
rm -rf "$l"
fi
done
# List
echo ----- Listing
find a
请注意,以上删除了-mtime +180
测试,因此您需要根据需要进行调整。输出将是这样的:
Created
----- Listing
a
a/b
a/b/c
a/b/c/2010
a/b/c/2010/05
a/b/c/2010/05/will-delete
a/b/c/2010/11
a/b/c/2010/11/will-delete
a/b/c/2010/11/will-ACD-leave
a/b/c/2011
a/b/c/2011/05
a/b/c/2011/05/will-delete
a/b/c/2011/11
a/b/c/2011/11/will-delete
a/b/c/2011/11/will-ACD-leave
a/b/d
a/b/d/2010
a/b/d/2010/05
a/b/d/2010/05/will-delete
a/b/d/2010/11
a/b/d/2010/11/will-delete
a/b/d/2010/11/will-ACD-leave
a/b/d/2011
a/b/d/2011/05
a/b/d/2011/05/will-delete
a/b/d/2011/11
a/b/d/2011/11/will-delete
a/b/d/2011/11/will-ACD-leave
----- Removing
Removing a/b/c/2010/05/will-delete
Removing a/b/c/2010/05
Removing a/b/c/2010/11/will-delete
Removing a/b/c/2011/05/will-delete
Removing a/b/c/2011/05
Removing a/b/c/2011/11/will-delete
Removing a/b/d/2010/05/will-delete
Removing a/b/d/2010/05
Removing a/b/d/2010/11/will-delete
Removing a/b/d/2011/05/will-delete
Removing a/b/d/2011/05
Removing a/b/d/2011/11/will-delete
----- Listing
a
a/b
a/b/c
a/b/c/2010
a/b/c/2010/11
a/b/c/2010/11/will-ACD-leave
a/b/c/2011
a/b/c/2011/11
a/b/c/2011/11/will-ACD-leave
a/b/d
a/b/d/2010
a/b/d/2010/11
a/b/d/2010/11/will-ACD-leave
a/b/d/2011
a/b/d/2011/11
a/b/d/2011/11/will-ACD-leave
上述操作将删除空的父文件夹,因此,如果这是问题所在,您可能需要修改循环while
以在每个文件夹后创建一个虚拟文件rm
,然后执行另一个顶层操作find
来删除这些文件(以某种方式命名它们以便于查找)。
另外需要注意的是,我建议不要删除,mv
而是在某处执行,直到您确定这是您想要的。之前备份是另一种选择。
希望这可以帮助。