Удалить все файлы, кроме самого последнего n, для каждой группы файлов. файлы с одним и тем же префиксом в каталоге

Вы говорите, что Gedit не является usng X11; который делает версия gtk-кварца это использует?

Возможно, это - osX определенный слой, используемый, который правильно не поддерживается gtk?см. также: https://bugzilla.gnome.org/show_bug.cgi? id=617583

5
04.11.2015, 00:35
4 ответа

Сценарий:

#!/bin/bash

# Get Prefixes

PREFIXES=$(ls | grep -Po '^(.*)(?!HT\d{4})-(.*)-(.*).tar.bz2$' | awk -F'-' '{print $1}' | uniq)

if [ -z "$1" ]; then
  echo need a number of keep files.
  exit 1
else
  NUMKEEP=$1
fi

for PREFIX in ${PREFIXES}; do

  ALL_FILES=$(ls -t ${PREFIX}*)

  if [ $(echo ${ALL_FILES} | wc -w) -lt $NUMKEEP ]; then
    echo Not enough files to be kept. Quit.
    continue
  fi

  KEEP=$(ls -t ${PREFIX}* | head -n${NUMKEEP})

  for file in $ALL_FILES ; do
    if [[ "$KEEP" =~ "$file" ]]; then
      echo keeping $file
    else
      echo RM $file
    fi
  done
done

Пояснение:

  • Вычислить префиксы:
    • Искать все файлы следуя регулярному выражению something-something-something.tar.bz2 , вырезать только первую часть до первого тире и сделать ее уникальной.
    • результатом является нормализованный список ПРЕФИКСОВ
  • Итерация по всем ПРЕФИКСАМ :
  • Вычислить ВСЕ_ФАЙЛЫ с помощью ПРЕФИКС
  • Проверить, если количество ALL_FILES меньше, чем количество файлов, которые нужно сохранить -> если true, мы можем остановиться на этом, удалять нечего
  • Вычислите файлы KEEP , которые являются наиболее последние NUMKEEP файлы
  • Просмотрите ALL_FILES и проверьте, нет ли данного файла в списке файлов KEEP . Если так: удалите.

Пример результата при запуске:

$ ./remove-old.sh 2
keeping bar-01-01.tar.bz2
keeping bar-01-02.tar.bz2
RM bar-01-03.tar.bz2
RM bar-01-04.tar.bz2
RM bar-01-05.tar.bz2
RM bar-01-06.tar.bz2
keeping foo-01-06.tar.bz2
keeping foo-01-05.tar.bz2
RM foo-01-04.tar.bz2
RM foo-01-03.tar.bz2
RM foo-01-02.tar.bz2

$ ./remove-old.sh 8
Not enough files to be kept. Quit.
Not enough files to be kept. Quit.
2
27.01.2020, 20:36

Как и было запрошено, этот ответ имеет тенденцию к «надежному и безопасному», как вы просили, в отличие от быстрого и грязного.

Переносимость: этот ответ работает в любой системе, содержащей sh , find , sed , sort , ls , grep , xargs и rm .

Сценарий никогда не должен заглушать большой каталог. Расширение имени файла оболочки не выполняется (что может заглушить слишком много файлов, но это огромное количество).

Этот ответ предполагает, что префикс не будет содержать тире ( - ).

Обратите внимание, что по умолчанию скрипт перечисляет только те файлы, которые будут удалены. Вы можете заставить его удалить файлы, направив вывод цикла while в xargs -d '/ n' rm , который закомментирован в сценарии. Таким образом, вы можете легко протестировать скрипт перед включением кода удаления.

#!/bin/sh -e

NUM_TO_KEEP=$(( 0 + ${1:-64000} )) || exit 1

find . -maxdepth 1 -regex '[^-][^-]*-[0-9][0-9]*-[0-9][0-9]*.tar.bz2' |
sed 's/-.*//; s,^\./,,' |
sort -u |
while read prefix
do
    ls -t | grep  "^$prefix-.*-.*\.tar\.bz2$" | sed "1,$NUM_TO_KEEP d"
done # | xargs -d '\n' rm --

Параметр N (количество сохраняемых файлов) по умолчанию равен 64000 (т. Е. Все файлы сохраняются).

Аннотированный код

Получите аргумент командной строки и проверьте целое число путем добавления, если не указано значение параметра по умолчанию 64000 (фактически все):

NUM_TO_KEEP=$(( 0 + ${1:-64000} )) || exit 1

Найти все файлы в текущем каталоге, которые соответствуют формату имени файла:

find . -maxdepth 1 -regex '[^-][^-]*-[0-9][0-9]*-[0-9][0-9]*.tar.bz2' |

Получить префикс: удалить все после префикса и удалить "./ "в начале:

sed 's/-.*//; s,^\./,,' |

Сортировка префиксов и удаление дубликатов ( -u - уникальный):

sort -u |

Прочитать каждый префикс и обработать:

while read prefix
do

Список всех файлов в каталоге, отсортированных по времени, выберите файлы для текущего префикса и удалите все строки за пределами файлов, которые мы хотим сохранить:

    ls -t | grep  "^$prefix-.*-.*\.tar\.bz2$" | sed "1,$NUM_TO_KEEP d"

Для тестирования закомментируйте код для удаления файла. Использование xargs, чтобы избежать проблем с длиной командной строки или пробелами в именах файлов, если они есть . Если вы хотите, чтобы сценарий создавал журнал, добавьте -v в rm , например: rm -v - . Удалите # ], чтобы активировать код удаления:

done # | xargs -d '\n' rm --

Если это сработает для вас, примите этот ответ и проголосуйте. Спасибо.

3
27.01.2020, 20:36

Я предполагаю, что файлы сгруппированы вместе по префиксу, если они перечислены в лексическом порядке. Это означает, что нет групп с префиксом, который является суффиксом другой группы, напримернет foo-1-2-3.tar.bz2 , который попадает между foo-1-1.tar.bz2 и foo-1-2.tar. bz2 . Исходя из этого предположения, мы можем перечислить все файлы, и когда мы обнаружим изменение префикса (или для самого первого файла), у нас появится новая группа.

#!/bin/bash
n=$1; shift   # number of files to keep in each group
shopt extglob
previous_prefix=-
for x in *-+([0-9])-+([0-9]).tar.bz2; do
  # Step 1: skip the file if its prefix has already been processed
  this_prefix=${x%-+([0-9])-+([0-9]).tar.bz2}
  if [[ "$this_prefix" == "$previous_prefix" ]]; then
    continue
  fi
  previous_prefix=$this_prefix
  # Step 2: process all the files with the current prefix
  keep_latest "$n" "$this_prefix"-+([0-9])-+([0-9]).tar.bz2
done

Теперь мы подошли к проблеме определения самых старых файлов среди явного списка .

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

keep_latest () (
  n=$1; shift
  if [ "$#" -le "$n" ]; then return; fi
  unset IFS; set -f
  set -- $(ls -t)
  shift "$n"
  rm -- "$@"
)
2
27.01.2020, 20:36

Я знаю, что это помечено bash, но я думаю, что это было бы проще с zsh:

#!/usr/bin/env zsh

N=$(($1 + 1))                         # calculate Nth to last
typeset -U prefixes                   # declare array with unique elements
prefixes=(*.tar.bz2(:s,-,/,:h))       # save prefixes in the array
for p in $prefixes                    # for each prefix
do
arr=(${p}*.tar.bz2)                   # save filenames starting with prefix in arr
if [[ ${#arr} -gt $1 ]]               # if number of elements is greather than $1
then
print -rl -- ${p}*.tar.bz2(Om[1,-$N]) # print all filenames but the most recent N 
fi
done

скрипт принимает один аргумент: n (количество файлов)
(:s,-,/,:h) - модификаторы glob, :s заменяет первые - на / и : h извлекает головку (часть до последней косой черты, которая в данном случае также является первой косой чертой, так как здесь только одна)
(Om[1,-$N]) - это глобальные классификаторы, Om сортирует файлы, начиная с самого старого, а [1,-$N] выбирает от первого до N-го последнего
. Если вы довольны результатом, замените print -rl на rm, чтобы действительно удалить файлы, например:

#!/usr/bin/env zsh

typeset -U prefixes
prefixes=(*.tar.bz2(:s,-,/,:h))
for p in $prefixes
arr=(${p}*.tar.bz2) && [[ ${#arr} -gt $1 ]] && rm -- ${p}*.tar.bz2(Om[1,-$(($1+1))])
1
27.01.2020, 20:36

Теги

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