haw*_*eye 6 directory shell-script date rm
我有以下路径:
/dir1/dir2/
Run Code Online (Sandbox Code Playgroud)
在这个路径中,我有以下包含各种(不相关)应用程序碎片的目录:
follower1234 1-Dec-2018
follower3456 2-Dec-2018
follower4567 3-Dec-2018
follower7890 9-Jan-2019
follower8901 10-Jan-2019
leader8765 4-Dec-2018
bystander6789 5-Dec-2018
Run Code Online (Sandbox Code Playgroud)
假设今天是 2019 年 1 月 10 日。
假设可以有任意数量的followerXXXX
,leaderXXXX
和bystanderXXXX
目录。
我想要的是删除所有followerXXXX
目录,但最新的followerXXX
目录已经超过两周。
现在我可以删除早于特定日期的所有目录。但这不是我的问题。我正在添加两个额外的参数。
在这种情况下,我想删除:
follower1234 1-Dec-2018
follower3456 2-Dec-2018
follower4567 3-Dec-2018
Run Code Online (Sandbox Code Playgroud)
但不是
follower7890 9-Jan-2019
follower8901 10-Jan-2019
leader8765 4-Dec-2018
bystander6789 5-Dec-2018
Run Code Online (Sandbox Code Playgroud)
即我想删除文件
(a) 匹配模式
(b) 超过两周
(c) 不是与模式匹配的最新目录(即保留最后一个)
我的问题是:如何删除超过 2 周的目录中的所有目录,但与文件模式匹配的最新目录除外?
问题已修改。
我的第一个选择(oneliner)与新规范不匹配,但在足够旧的目录中保存了最新的目录,可以删除(超过 14 天)。
我做了第二个选择,(shellscript)使用
@ 自 1970 年 1 月 1 日,格林威治标准时间 00:00 以来的秒数,带小数部分。
并减去对应于 14 天的秒数,seclim
以获得排序目录列表中“秒数限制”的时间戳。
以前的答案干净漂亮,但它们没有保留最新的follower
目录。以下命令行将执行此操作(并且可以管理带有空格的名称,但带有换行符的名称会产生问题),
find . -type d -name "follower*" -printf "%T+ %p\n"|sort|head -n -1 | cut -d ' ' -f 2- | sed -e 's/^/"/' -e 's/$/"/' | xargs echo rm -r
Run Code Online (Sandbox Code Playgroud)
在此目录结构上进行测试,
$ find -printf "%T+ %p\n"|sort
2019-01-10+13:11:40.6279621810 ./follower1
2019-01-10+13:11:40.6279621810 ./follower1/2/3
2019-01-10+13:11:40.6279621810 ./follower1/2/dirnam with spaces
2019-01-10+13:11:40.6279621810 ./follower1/2/name with spaces
2019-01-10+13:11:56.5968732640 ./follower1/2/file
2019-01-10+13:13:18.3975675510 ./follower2
2019-01-10+13:13:19.4016254340 ./follower3
2019-01-10+13:13:20.4056833250 ./follower4
2019-01-10+13:13:21.4097412230 ./follower5
2019-01-10+13:13:22.4137991260 ./follower6
2019-01-10+13:13:23.4138568040 ./follower7
2019-01-10+13:13:24.4219149500 ./follower8
2019-01-10+13:13:25.4259728780 ./follower9
2019-01-10+13:15:34.4094596830 ./leader1
2019-01-10+13:15:36.8336011960 .
2019-01-10+13:15:36.8336011960 ./leader2
2019-01-10+13:25:03.0751878450 ./follower1/2
Run Code Online (Sandbox Code Playgroud)
像这样,
$ find . -type d -name "follower*" -printf "%T+ %p\n"|sort|head -n -1 | cut -d ' ' -f 2- | sed -e 's/^/"/' -e 's/$/"/' | xargs echo rm -r
rm -r ./follower1 ./follower2 ./follower3 ./follower4 ./follower5 ./follower6 ./follower7 ./follower8
Run Code Online (Sandbox Code Playgroud)
Sofollower9
被排除,因为它是最新的follower
目录(具有名称的目录,不以follower
(开头leader1
,leader2
并且2
不在游戏中)。
现在我们添加时间标准,-mtime +14
并进行另一次“试运行”以检查它是否像应有的那样工作,当我们将目录更改为有实际follower
目录的位置时,
find . -type d -name "follower*" -mtime +14 -printf "%T+ %p\n"|sort|head -n -1 | cut -d ' ' -f 2- | sed -e 's/^/"/' -e 's/$/"/' | xargs echo rm -r
Run Code Online (Sandbox Code Playgroud)
最后我们删除echo
并拥有一个可以做我们想做的命令行,
find . -type d -name "follower*" -mtime +14 -printf "%T+ %p\n"|sort|head -n -1 | cut -d ' ' -f 2- | sed -e 's/^/"/' -e 's/$/"/' | xargs rm -r
Run Code Online (Sandbox Code Playgroud)
find
在当前目录中,名称以 开头的目录,follower
自 14 天前未修改。head -n -1
会排除最新的follower
目录。xargs
作为参数通过管道传输到rm -r
以删除我们想要删除的目录。我做了第二个选择,(shellscript)使用
@ seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
Run Code Online (Sandbox Code Playgroud)
它也有两个选项,
-n
试运行-v
冗长的
我根据 OP 的要求修改了 shellscript:在单引号内输入模式作为参数,例如“follower*”。
我建议 shellscript 的名称是prune-dirs
因为它现在更通用(不再只是prune-followers
修剪目录follower*
)。
建议您第一次使用这两个选项运行 shellscript 以“查看”您将执行的操作,当它看起来正确时,删除-n
以使 shellscript 删除足够旧的目录以被删除。因此,让我们调用它prune-dirs
并使其可执行。
#!/bin/bash
# date sign comment
# 2019-01-11 sudodus version 1.1
# 2019-01-11 sudodus enter the pattern as a parameter
# 2019-01-11 sudodus add usage
# 2019-01-14 sudodus version 1.2
# 2019-01-14 sudodus check if any parameter to the command to be performed
# Usage
usage () {
echo "Remove directories found via the pattern (older than 'datint')
Usage: $0 [options] <pattern>
Examples: $0 'follower*'
$0 -v -n 'follower*' # 'verbose' and 'dry run'
The 'single quotes' around the pattern are important to avoid that the shell expands
the wild card (for example the star, '*') before it reaches the shellscript"
exit
}
# Manage options and parameters
verbose=false
dryrun=false
for i in in "$@"
do
if [ "$1" == "-v" ]
then
verbose=true
shift
elif [ "$1" == "-n" ]
then
dryrun=true
shift
fi
done
if [ $# -eq 1 ]
then
pattern="$1"
else
usage
fi
# Command to be performed on the selected directories
cmd () {
echo rm -r "$@"
}
# Pattern to search for and limit between directories to remove and keep
#pattern='follower*'
datint=14 # days
tmpdir=$(mktemp -d)
tmpfil1="$tmpdir"/fil1
tmpfil2="$tmpdir"/fil2
secint=$((60*60*24*datint))
seclim=$(date '+%s')
seclim=$((seclim - secint))
printf "%s limit-in-seconds\n" $seclim > "$tmpfil1"
if $verbose
then
echo "----------------- excluding newest match:"
find . -type d -name "$pattern" -printf "%T@ %p\n" | sort |tail -n1 | cut -d ' ' -f 2- | sed -e 's/^/"/' -e 's/$/"/'
fi
# exclude the newest match with 'head -n -1'
find . -type d -name "$pattern" -printf "%T@ %p\n" | sort |head -n -1 >> "$tmpfil1"
# put 'limit-in-seconds' in the correct place in the sorted list and remove the timestamps
sort "$tmpfil1" | cut -d ' ' -f 2- | sed -e 's/^/"/' -e 's/$/"/' > "$tmpfil2"
if $verbose
then
echo "----------------- listing matches with 'limit-in-seconds' in the sorted list:"
cat "$tmpfil2"
echo "-----------------"
fi
# create 'remove task' for the directories older than 'limit-in-seconds'
params=
while read filnam
do
if [ "${filnam/limit-in-seconds}" != "$filnam" ]
then
break
else
params="$params $filnam"
fi
done < "$tmpfil2"
cmd $params > "$tmpfil1"
cat "$tmpfil1"
if ! $dryrun && ! test -z "$params"
then
bash "$tmpfil1"
fi
rm -r $tmpdir
Run Code Online (Sandbox Code Playgroud)
follower
子目录的目录prune-dirs
并使用两个选项运行 -v -n
cd directory-with-subdirectories-to-be-pruned/
nano prune-dirs # copy and paste into the editor and save the file
chmod +x prune-dirs
./prune-dirs -v -n
Run Code Online (Sandbox Code Playgroud)我prune-dirs
在具有以下子目录的目录中进行了测试,如find
$ find . -type d -printf "%T+ %p\n"|sort
2018-12-01+02:03:04.0000000000 ./follower1234
2018-12-02+03:04:05.0000000000 ./follower3456
2018-12-03+04:05:06.0000000000 ./follower4567
2018-12-04+05:06:07.0000000000 ./leader8765
2018-12-05+06:07:08.0000000000 ./bystander6789
2018-12-06+07:08:09.0000000000 ./follower with spaces old
2019-01-09+10:11:12.0000000000 ./follower7890
2019-01-10+11:12:13.0000000000 ./follower8901
2019-01-10+13:15:34.4094596830 ./leader1
2019-01-10+13:15:36.8336011960 ./leader2
2019-01-10+14:08:36.2606738580 ./2
2019-01-10+14:08:36.2606738580 ./2/follower with spaces
2019-01-10+17:33:01.7615641290 ./follower with spaces new
2019-01-10+19:47:19.6519169270 .
Run Code Online (Sandbox Code Playgroud)
用法
$ ./prune-dirs
Remove directories found via the pattern (older than 'datint')
Usage: ./prune-dirs [options] <pattern>
Examples: ./prune-dirs 'follower*'
./prune-dirs -v -n 'follower*' # 'verbose' and 'dry run'
The 'single quotes' around the pattern are important to avoid that the shell expands
the wild card (for example the star, '*') before it reaches the shellscript
Run Code Online (Sandbox Code Playgroud)
运行-v -n
(详细的试运行)
$ ./prune-dirs -v -n 'follower*'
----------------- excluding newest match:
"./follower with spaces new"
----------------- listing matches with 'limit-in-seconds' in the sorted list:
"./follower1234"
"./follower3456"
"./follower4567"
"./follower with spaces old"
"limit-in-seconds"
"./follower7890"
"./follower8901"
"./2/follower with spaces"
-----------------
rm -r "./follower1234" "./follower3456" "./follower4567" "./follower with spaces old"
Run Code Online (Sandbox Code Playgroud)
具有更通用模式的详细试运行
$ LANG=C ./prune-dirs -v -n '*er*'
----------------- excluding newest match:
"./follower with spaces new"
----------------- listing matches with 'limit-in-seconds' in the sorted list:
"./follower1234"
"./follower3456"
"./follower4567"
"./leader8765"
"./bystander6789"
"./follower with spaces old"
"limit-in-seconds"
"./follower7890"
"./follower8901"
"./leader1"
"./leader2"
"./2/follower with spaces"
-----------------
rm -r "./follower1234" "./follower3456" "./follower4567" "./leader8765" "./bystander6789" "./follower with spaces old"
Run Code Online (Sandbox Code Playgroud)
不带任何选项运行(删除目录的真实案例)
$ ./prune-dirs 'follower*'
rm -r "./follower1234" "./follower3456" "./follower4567" "./follower with spaces old"
Run Code Online (Sandbox Code Playgroud)
以-v
“再试一次”运行
$ LANG=C ./prune-dirs -v 'follower*'
----------------- excluding newest match:
"./follower with spaces new"
----------------- listing matches with 'limit-in-seconds' in the sorted list:
"limit-in-seconds"
"./follower7890"
"./follower8901"
"./2/follower with spaces"
-----------------
rm -r
Run Code Online (Sandbox Code Playgroud)
shellscript 没有列出任何目录“above”“limit-in-seconds”,并且没有为rm -r
命令行列出文件,所以工作已经完成(这是正确的结果)。但是,如果几天后再次运行 shellscript,可能会在“秒数限制”的“上方”找到一些新目录并被删除。
补充罗文的答案。您可以通过目录路径更改点
find . -type d -name follower* -mtime +14 -exec rm -rf {} +;
Run Code Online (Sandbox Code Playgroud)
与zsh
:
(){ n=$#; } follower<->(/) # count the number of follower<n> dirs
to_remove=(follower<->(/m+13om)) # assumes the dir list is not changed
# since the previous command
(($#to_remove < n)) || to_remove[1]=() # keep the youngest if they're
# all over 2 weeks old
echo rm -rf $to_remove
Run Code Online (Sandbox Code Playgroud)
(echo
开心时删除)
<->
任何十进制数字序列(<1-20>
无约束的缩写形式)。(){code} args
: 匿名函数,这里将其参数数量存储在$n
.(/omm+13)
: 全局限定符/
: 只选择目录类型的文件(相当于find
's -type d
)m+13
: 全天存在时间严格大于 13 天的文件,因此存在 14 天或更早的文件(相当于find
's -mtime +13
)。om
: 按修改时间排序(像ls -t
年轻的文件优先)请注意,依赖目录修改时间是危险的。当在其中添加、删除或重命名文件时(或当它们被touch
编辑时),目录会被修改。由于这些目录已编号,因此您可能希望改用该编号,因此将其替换om
为nOn
(由ame以n
umerically rder O
in reverse (capital O
)代替n
)。
要在变量中包含模式,请替换follower<->
为$~pattern
和设置pattern='follower<->'
或任何其他值。