我有两个文件夹:“/media/downloads/”和“/home/uploads/” 我想删除“/media/downloads/”上 15 年前的文件(如果“/home/uploads/”中存在)
执行此操作的最佳脚本是什么?
先感谢您。
答案1
和zsh
:
cd /home/uploads
uploaded_files=( **/*(ND.) )
cd /media/downloads
old_downloads=( **/*(ND.m+14) )
echo rm -- ${old_downloads:*uploaded_files}
(删除echo
来实际删除文件)。
/media/downloads
如果相同路径下的常规文件存在于/home/uploads
.请注意,它不会检查它们是否具有相同的内容。
作为一个脚本,它可能看起来像:
#! /bin/zsh -
die() {
print -ru2 -C1 -- "$@"
exit 1
}
usage() {
die "$@" "Usage: $ZSH_SCRIPT:t [-d <days>] [-n] <srcdir> <dstdir>" \
'' \
' Removes files from <srcdir> if their age rounded down to an' \
' integer number of days is strictly greater than <days> (14 by' \
' default). -n for dry-run'
exit 1
}
zmodload zsh/system || die
dryrun=0 days=14
while getopts nd: o; do
case $o in
(n) dryrun=1;;
(d) days=$OPTARG;;
(*) usage;;
esac
done
shift OPTIND-1
(( $# == 2 )) || usage
[[ $days = <0-> ]] || usage "$days is not a positive decimal integer"
src=$1 dst=$2
[[ -d $src ]] || die "$src is not a directory"
[[ -d $dst ]] || die "$dst is not a directory"
list() {
local dir=$1 var=$2 qual=$3 err
ERRNO=0
() { eval $var'=( "${@#$dir/}" )'; } $dir/**/*(ND.$qual)
if (( ERRNO )); then
syserror -e err
die "An error was encountered during $dir traversal: $err"
fi
}
list $src old_in_src m+$days
list $dst all_in_dst oN
to_remove=( ${old_in_src:*all_in_dst} )
if (( dryrun )); then
if (( $#to_remove )); then
print -ru2 -C1 "$#old_in_src old files found in $src, out of which $#to_remove are also found in $dst:" ' - '$^to_remove
else
print -ru2 "No file found to remove ($#old_in_src old files in $src in total)"
fi
else
rm -f -- $src/$^to_remove
fi
答案2
使用find
和bash
:
find /media/downloads/ -type f -mtime +15 \
-exec bash -c 'for f; do
f2=${f/"/media/downloads/"/}
test -e "/home/uploads/$f2" && delfiles+=("$f");
done;
[ -n "$delfiles" ] && printf "rm %q\n" -- "${delfiles[@]}"' bash {} +
find
查找所有超过 15 天的常规文件,并将它们作为参数传递给bash
.对于每个文件名,bash 会从文件名中删除顶级目录 ( /media/downloads/
),然后检查文件名的其余部分(包括子目录,如果有的话)是否存在于/home/uploads/
.如果是,则会将该文件添加到名为 的数组中$delfiles
。
一旦迭代完所有文件名参数,它就会打印数组中的每个文件名。
这是作为试运行编写的,因此只会展示如果不实际做的话它会做什么。要使其真正删除文件,请更改printf "rm %q\n" --
为rm --
它永远不会删除任何目录,即使它们的内容被删除后是空的。如果您需要这样做,您可以在删除文件后运行如下命令(使用 GNU find)。
find /media/downloads/ -mindepth 1 -type d -empty -delete
另外值得注意的是: 和 都zsh
具有类似的参数扩展和字符串修改功能,因此使用or代替 bashksh
应该很简单(可能只需要更改为or但我还没有测试过,所以不能肯定地说- bash 和那些 shell 之间可能存在细微差别)。zsh
ksh
bash -c
ksh -c
zsh -c
¹查看man find
并搜索-atime
有关如何计算的详细信息 - 您可能会发现它-mtime 14
更适合您。如果感兴趣的话,查找的-daystart
选项也可能是。