Я пытаюсь изменить следующую команду в сценарии, который удаляет каталоги в зависимости от возраста.

Пример каталогов будет следующим:

/a/b/c/2011/11/11
/a/b/c/2011/11/11/12-ACD-1234
/a/b/c/2011/11/14

Текущая неточная попытка выглядит следующим образом:

find /a/b -type d -mindepth 2 -depth ! -name '*ACD*' -mtime +180 -exec rm -rf {} +

Хотя этот сценарий не удалит каталоги, содержащие "ACD", родительский каталог будет удален. Я пробовал комбинации с -prune и другие трюки, но не смог получить желаемый результат.

Есть ли способ отточить эту команду поиска, чтобы сохранить подкаталоги, соответствующие определенным критериям? В этом примере родительские каталоги /a /b /c /2011 и /a /b /c /2011/11 должны быть сохранены, чтобы не рекурсивно удалять подкаталог.

Я пытаюсь сделать это с помощью команды поиска, если это вообще возможно.

2 ответа2

0

Не уверен, что вы можете сделать это только с помощью find , но вот тестовый скрипт, который вы можете попробовать - попробуйте это в /tmp или где-нибудь в безопасности:

# Prepare
rm -rf a
mkdir -p a/b/c
for a in c d; do
  for i in 2010 2011; do
    for j in 05 11; do
      mkdir -p a/b/$a/$i/$j/will-delete
      if [ $j != 05 ]; then
        mkdir -p a/b/$a/$i/$j/will-ACD-leave
      fi
    done
  done
done
echo Created

# List
echo ----- Listing
find a

# Remove
echo ----- Removing
find a/b -depth -type d ! -name "*ACD*"|while read l; do
  num_entries=`ls -a "$l"|wc -l`
  if [ $num_entries -eq 2 ]; then
    echo Removing $l
    rm -rf "$l"
  fi
done

# List
echo ----- Listing
find a

Обратите внимание, что вышеперечисленное удаляет -mtime +180 для тестирования, поэтому вам нужно настроить его по мере необходимости. Выход будет такой:

Created
----- Listing
a
a/b
a/b/c
a/b/c/2010
a/b/c/2010/05
a/b/c/2010/05/will-delete
a/b/c/2010/11
a/b/c/2010/11/will-delete
a/b/c/2010/11/will-ACD-leave
a/b/c/2011
a/b/c/2011/05
a/b/c/2011/05/will-delete
a/b/c/2011/11
a/b/c/2011/11/will-delete
a/b/c/2011/11/will-ACD-leave
a/b/d
a/b/d/2010
a/b/d/2010/05
a/b/d/2010/05/will-delete
a/b/d/2010/11
a/b/d/2010/11/will-delete
a/b/d/2010/11/will-ACD-leave
a/b/d/2011
a/b/d/2011/05
a/b/d/2011/05/will-delete
a/b/d/2011/11
a/b/d/2011/11/will-delete
a/b/d/2011/11/will-ACD-leave
----- Removing
Removing a/b/c/2010/05/will-delete
Removing a/b/c/2010/05
Removing a/b/c/2010/11/will-delete
Removing a/b/c/2011/05/will-delete
Removing a/b/c/2011/05
Removing a/b/c/2011/11/will-delete
Removing a/b/d/2010/05/will-delete
Removing a/b/d/2010/05
Removing a/b/d/2010/11/will-delete
Removing a/b/d/2011/05/will-delete
Removing a/b/d/2011/05
Removing a/b/d/2011/11/will-delete
----- Listing
a
a/b
a/b/c
a/b/c/2010
a/b/c/2010/11
a/b/c/2010/11/will-ACD-leave
a/b/c/2011
a/b/c/2011/11
a/b/c/2011/11/will-ACD-leave
a/b/d
a/b/d/2010
a/b/d/2010/11
a/b/d/2010/11/will-ACD-leave
a/b/d/2011
a/b/d/2011/11
a/b/d/2011/11/will-ACD-leave

Выше будет удалять пустые родительские папки, так что если это проблема, вы можете изменить while цикла , чтобы просто сделать фиктивный файл после каждого rm , а затем сделать еще на высшем уровне find , чтобы удалить их (назовите их каким - то образом для облегчения находка).

Как отдельное примечание - вместо удаления я предлагаю сделать где-нибудь mv пока вы не уверены, что это то, что вы хотите. Резервное копирование перед другим вариантом.

Надеюсь это поможет.

-1

Главная проблема заключается в том, что find дает вам прекрасный список каталогов в качестве вывода, но вам нужен способ оценить каждый из них самостоятельно, чтобы определить, есть ли у них *ACD* где-то в подкаталоге. И, по-видимому, конвейерные команды не работают хорошо (или вообще?) в качестве аргумента для поиска -exec .

Таким образом, один из подходов заключается в создании собственного командного сценария, который может вызывать -exec , который будет возвращать 0, если его аргумент не содержит подкаталога *ACD* , и 1 в противном случае. Кажется, это работает для меня:

#!/bin/sh
# script: /path/to/hasnoACD
list=`find $1 -name '*ACD*'`
[ "x$list" = "x" ] && exit 0 || exit 1

Тогда желаемая команда поиска просто использует -exec дважды:

find /a/b -type d -mindepth 2 -depth ! -name '*ACD*' -mtime +180 -exec /path/to/hasnoACD {} \;  -exec rm -rf {} +

-exec /path/to/hasnoACD {} \; оценит как истинное только для тех случаев, которые вы хотите.


Другая альтернатива: я изначально подошел к этому способом, похожим на @ icyrock-com, в результате я нашел команду find, переданную в цикл while, который обрабатывает удаление каталогов. Синтаксис while будет зависеть от вашей оболочки, и вам понадобится способ различать каталоги, которые содержат некоторый подкаталог *ACD* как мы делали выше со hasnoACD , но в bash на FreeBSD, похоже, работает следующее:

find /a/b -type d -mindepth 2 -depth ! -name '*ACD*' -mtime +180 | while read mydir ; do find $mydir -name '*ACD*' | xargs false && rm -rf $mydir ; done

Обратите внимание на поиск внутри цикла while - только когда этот поиск ничего не возвращает (без подкаталогов *ACD* ), xargs возвращает true, так что выполняется rm -rf $mydir . Такое поведение xargs работает на моей машине с FreeBSD, но в Linux или Solaris поведение отличается, поэтому потребуется другой тест.

Как говорит @ icyrock-com, вы можете захотеть сделать mv а не rm , просто чтобы быть в безопасности.

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