Я храню некоторые данные в файлах, которые следуют этому соглашению об именах:

/interesting/data/filename-YYYY-MM-DD-HH-MM

Как мне найти те с date in file name < now - 1 month и удалить их?

Файлы могли измениться с момента их создания, поэтому поиск по last modification date не годится.

То, что я делаю сейчас, это их фильтрация в python:

prefix = '/interesting/data/filename-'

import commands
names = commands.getoutput('ls {0}*'.format(prefix)).splitlines()

from datetime import datetime, timedelta

all_files = map(lambda name: {
    'name': name,
    'date': datetime.strptime(name, '{0}%Y-%m-%d-%H-%M'.format(prefix))
}, names)

month = datetime.now() - timedelta(days = 30)
to_delete = filter(lambda item: item['date'] < month, all_files)

import os
from operator import itemgetter
map(os.remove, map(itemgetter('name'), to_delete))

Есть ли (oneliner) решение для bash для этого?

2 ответа2

1

Можете ли вы использовать -ctime с find? Для файла ctime указывает время последнего изменения метаданных файла (создание файла, переименование, chmod, chown, chgrp и т.д.). Для большинства лог-файлов дата создания и ctime будут одинаковыми.

1

Предполагая дату GNU и GNU находят, вы можете сделать это следующим образом

#!/usr/bin/env bash

prefix="/interesting/data/filename-"
ref=/tmp/ref.$$
one_month_ago=/tmp/one_month_ago.$$
results=/tmp/results.$$

# create a file whose timestamp is "one month ago"
touch "$one_month_ago" -t $(date -d "-1 month" +%Y%m%d%I%M.%S)

while read -r file ; do
        # strip the prefix, leaving the suffix
        datestr=$(tail -c $(( ${#file} - ${#prefix} + 1 )) <<<"$file")

        # cut the date and time out of the suffix
        date=$(cut -d- -f1-3 <<<"$datestr")
        time=$(cut -d- -f 4- <<<"$datestr" | tr - :)

        # create a reference file whose timestamp matches the string from $file
        touch "$ref" -t $(date -d "$date $time" +%Y%m%d%I%M.%S)

        # ask find whether the reference file is not neewer (aka "is older") 
        # than one month ago
        find "$ref" -not -newer "$one_month_ago" > "$results" &&
                # results from find?
                [ -s "$results" ] &&
                # then rm the corresponding file
                echo rm -f -- "$file"

done < <(find -path "$prefix"'*')

# clean up
rm -f "$ref" "$one_month_ago" "$results"

Но это не совсем лайнер.

Поскольку это проверено и несколько опасно, я включил префикс echo в команду rm , поэтому вам нужно удалить его, как только вы убедитесь, что результаты верны.

Один недостаток здесь заключается в первоначальном выборе файлов. -path "$prefix"'*' предполагает абсолютные пути и в противном случае будет ломаться; более разумный выбор, вероятно, лучше, даже если это простой глобус оболочки (т. е. замените цикл while на for file in "$prefix*" ; do ... done . Я не сделал этого, потому что я не знаю, будет ли такое расширение глобуса переполнять максимальную длину команды.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .