我想要一个 shell 脚本,保留所有时间戳与当前时间相同的月份的文件 + 之前的最新文件,并删除目录中的其余文件。
存储在目录中的所有文件名的结构name$timestamp.extension
如下
timestamp=`date "+%Y%m%d-%H%M%S"`
所以,这意味着如果目录中有以下文件:
name161214-082211.gz
name161202-082211.gz
name161020-082211.gz
name161003-082211.gz
name161001-082211.gz
执行此代码后目录中剩余的文件将是:
name161214-082211.gz
name161202-082211.gz
name161020-082211.gz
附言。对于 shell 来说非常新。不仅希望拥有一个可以工作的代码,而且还希望能够学习。所以,如果您愿意的话,请也解释一下代码。谢谢你!
答案1
和zsh
你一起可以做类似的事情
# get current date (YYMM) in a variable
crd=$(date "+%y%m")
# use a function to extract the 13 chars that make up the timestamp
dtts() REPLY=${${REPLY%%.*}: -13}
# sort file names by the timestamp in descending order, exclude the ones with the
# same YYMM as the current date and set the remaining file names as arguments
set -- *(.O+dtts^e_'[[ "${${REPLY%%.*}: -13:4}" == "$crd" ]]'_)
# remove the first item from the list (i.e. the last one before current month)
shift
# print the remaining file names
print -rl -- "$@"
这使用参数扩展和全局限定符:它首先使用该函数选择常规文件 (.) 按时间戳
降序排序 ( ),然后如果时间戳与当前年份和月份匹配(即如果引号内的表达式返回 true),则否定字符串取消选择文件;然后从列表中删除第一项(因为名称按降序排序,这将是当前月份之前的最新时间戳)如果您对结果满意, 请替换为。O
dtts
e
^e_'[[ "${${REPLY%%.*}: -13:4}" == "$crd" ]]'_
shift
print -rl
rm
答案2
bash 解决方案是:
#!/bin/bash
keep=$(date '+%y%m')
rm `find . -name "name*" -and -not -name "name$keep*" | sort | head -n-1`
- 将变量 $keep 设置为当前年份(2 位数字)和月份。
- 删除反引号括起来的代码的结果是
-
- 查找当前目录(和子目录)中以“name”开头且不以“name$keep”开头的所有文件名
-
- 对结果进行排序
-
- 删除最后一行
但是,在这种情况下我不会使用纯 shell 脚本,因为代码可能会很快变得复杂(因此难以维护)。
你可以使用 perl (或 python)代替:
#!/usr/bin/env perl
use strict;
use warnings;
use POSIX qw(strftime);
# collect the names of all files older than current month.
# we assume that there are no files from future.
my $keep_date = strftime("%y%m", localtime);
my @files = sort grep {!/^name$keep_date/} glob "*.gz";
# the newest file from the collected files shall not be deleted
pop @files;
# delete all collected files
map {unlink} @files;
或直接从命令行:
perl -We 'use POSIX qw(strftime); my $keep_date = strftime("%y%m", localtime); my @files = sort grep {!/^name$keep/} glob "*.gz"; pop @files; map {unlink} @files;'
答案3
另一种zsh
方法:
# today as YYMMDD using prompt expansion
now=${(%):-%D{%y%m%d}}
# construct patterns
month="name<$now[1,4]01-$now>-<->.gz" all="name<-$now>-<->.gz"
# perform globbing (expand patterns to list of matching files)
month=($~month(N)) all=($~all)
() (rm -f -- $argv[1,-2]) ${all:|month}
这是使用${all:|month}
数组减法,其中$all
数组是根据中的文件列表构建的到现在为止的任何日期范围并$month
从文件列表中构建每月第一天至今范围。