保留当月的所有文件+之前的最新文件,删除其余的

保留当月的所有文件+之前的最新文件,删除其余的

我想要一个 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),则否定字符串取消选择文件;然后从列表中删除第一项(因为名称按降序排序,这将是当前月份之前的最新时间戳)如果您对结果满意, 请替换为。Odttse^e_'[[ "${${REPLY%%.*}: -13:4}" == "$crd" ]]'_shift
print -rlrm

答案2

bash 解决方案是:

#!/bin/bash

keep=$(date '+%y%m')
rm `find . -name "name*" -and -not -name "name$keep*" | sort | head -n-1`
  • 将变量 $keep 设置为当前年份(2 位数字)和月份。
  • 删除反引号括起来的代码的结果是
    1. 查找当前目录(和子目录)中以“name”开头且不以“name$keep”开头的所有文件名
    1. 对结果进行排序
    1. 删除最后一行

但是,在这种情况下我不会使用纯 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从文件列表中构建每月第一天至今范围。

相关内容