Работа с датами

У меня есть задача, которую я могу придумать логику, но не могу реализовать в Unix.

У меня есть каталог, подкаталоги которого имеют шаблон именования «mmddyy». Итак, моя задача здесь - удалить все каталоги старше X дней. Рассматриваемая метка даты - это не метка времени Unix, а метка даты, похожая на имя каталога.

Мой подход:

  1. Получить список имен каталогов в массиве
  2. Если (SYSDATE - массив> 30), затем удалить, остальное продолжить.

Как решить проблему с помощью Unix?

-1
22.09.2017, 17:27
2 ответа

Сzsh:

#! /usr/bin/env zsh
days=${1-30}

zmodload zsh/datetime || exit

strftime -s cutoff %Y%m%d $((EPOCHSECONDS - days * 24 * 60 * 60))

old_enough() {
  year=$REPLY[5,6]
  ((year += 1900 + (year < 70) * 100))
  [[ $year$REPLY[1,4] < $cutoff ]]
}

set -o extendedglob
echo rm -rf [0-9](#c6)(/+old_enough)

Удалите echoили подключитесь к sh, если все устраивает.

Для ksh93эквивалентом может быть:

#! /usr/bin/env ksh
days=${1-30}

cutoff=$(printf '%(%Y%m%d)T' "$days days ago")

old_enough() {
  year=${1:4}
  ((year += 1900 + (year < 70) * 100))
  [[ $year${1:0:4} < $cutoff ]]
}
dirs=()
for f in {6}([0-9]); do
  [ -d "$f" ] && [ ! -L "$f" ] && old_enough "$f" && dirs+=("$f")
done
if ((${#dirs[@]})); then
  echo rm -rf "${dirs[@]}"
else
  echo >&2 "No match"
  exit 1
fi

Для bashэквивалентом может быть:

#! /usr/bin/env bash
days=${1-30}

printf -v now '%(%s)T' -1
printf -v cutoff '%(%Y%m%d)T' "$((now - days * 24 * 60 * 60))"

old_enough() {
  year=${1:4}
  year=${year#0} # work around bug where bash complains about 08 and 09
  ((year += 1900 + (year < 70) * 100))
  [[ $year${1:0:4} < $cutoff ]]
}
shopt -s nullglob
dirs=()
for f in [0-9][0-9][0-9][0-9][0-9][0-9]; do
  [ -d "$f" ] && [ ! -L "$f" ] && old_enough "$f" && dirs+=("$f")
done
if ((${#dirs[@]})); then
  echo rm -rf "${dirs[@]}"
else
  echo >&2 "No match"
  exit 1
fi

Годы старше 70 считаются прошлым веком(123199означает 1999 -12 -31, 092217означает 2017 -09 -22 ).

Если у вас нет ни одной из этих оболочек и вы используете систему Unix (, а не GNU (UNG )), тогда лучше всего прибегнуть кperl:

#! /usr/bin/env perl
use POSIX;
$cutoff = time - ($ARGV[0] // 30) * 24 * 60 * 60;
$, = " "; $\ = "\n";
if (@dirs = grep {
    /^(\d\d)(\d\d)(\d\d)$/ && ! -l && -d && 
    mktime(0,0,0,$2,$1-1,$3+100*($3<70)) < $cutoff} <*>) {
  print "rm -rf", @dirs;
} else {
  die "No match";
}
0
28.01.2020, 05:10
then=$( date -d '30 days ago' +%y%m%d )

for d in *; do
    if [[ -d "$d" ]] && [[ "$d" =~ ^([0-9][0-9])([0-9][0-9])([0-9][0-9])$ ]]; then
        datestring="${BASH_REMATCH[3]}${BASH_REMATCH[1]}${BASH_REMATCH[2]}"

        if [[ "$datestring" < "$then" ]]; then
            echo rm -rf "$d"
        fi
    fi
done

Этот скрипт bashсначала вычислит дату 30 дней назад с помощью GNU dateи сохранит ее в формате YYMMDDв $then.

Затем выполняется итерация по именам, найденным в текущем каталоге. Если какое-либо из найденных имен является каталогом, соответствующим заданному регулярному выражению, он выбирает части имени каталога и упорядочивает их в формате YYMMDDв $datestring.

Если $datestringлексикографически меньше, чем $then, то этот каталог следует удалить. echoпредотвращает это на самом деле, поэтому сначала запустите его несколько раз, чтобы убедиться, что он работает, прежде чем удалять его.

Тестирование:

$ mkdir {01..12}0117  # one directory for the 1st of every month this year
$ bash./script.sh
rm -rf 010117
rm -rf 020117
rm -rf 030117
rm -rf 040117
rm -rf 050117
rm -rf 060117
rm -rf 070117
rm -rf 080117

(сегодняшняя дата 170922, а $thenимеет значение170823)

Очевидно, что это не удастся для имен каталогов, содержащих даты прошлого века, (они не будут удалены ).

0
28.01.2020, 05:10

Теги

Похожие вопросы