Como posso usar o comando find para remover diretórios sem eliminar certos subdiretórios?

0

Estou tentando modificar o seguinte comando em um script que remove diretórios com base na idade.

Exemplos de diretórios seriam os seguintes:

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

A atual tentativa imprecisa é a seguinte:

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

Embora este script não remova diretórios contendo "ACD", o diretório pai será removido. Eu tentei -primas combinações e outros truques, mas sou incapaz de obter o resultado desejado.

Existe uma maneira de aprimorar esse comando de localização para preservar subdiretórios que atendem a determinados critérios? Neste exemplo, os diretórios pai / a / b / c / 2011 e / a / b / c / 2011/11 teriam que ser preservados para não remover recursivamente o subdiretório.

Estou procurando fazer isso apenas com um comando de localização, se possível.

    
por Linux2012 21.02.2012 / 03:13

2 respostas

-1

A principal questão é que o find fornece uma linda lista de diretórios como saída, mas você precisa avaliar cada um deles por conta própria para determinar se eles têm um *ACD* em algum lugar em um subdiretório. E os comandos canalizados não parecem funcionar bem (ou de todo?) Como um argumento para encontrar -exec .

Portanto, uma abordagem seria criar seu próprio script de comando que -exec possa chamar, que retornará 0 se seu argumento não contiver subdiretório *ACD* e 1 caso contrário. Isso parece funcionar para mim:

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

Então seu comando de busca desejado apenas usa -exec duas vezes:

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

-exec /path/to/hasnoACD {} \; será avaliado como verdadeiro apenas para os casos desejados.


Outra alternativa: eu inicialmente me aproximei disso de uma maneira similar ao @ icyrock-com, em que acabei com um comando de busca canalizado para um loop while, que lida com as remoções de diretório. A sintaxe 'while' dependerá do seu shell, e você precisará de uma maneira de distinguir diretórios que contenham alguns subdiretórios *ACD* como fizemos acima com o script hasnoACD , mas no bash no FreeBSD o seguinte parece funcionar:

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

Observe a localização dentro do loop while - somente quando esse find não retornar nada (no *ACD* subdirs) os xargs retornarão true, para que o rm -rf $mydir seja executado. Esse comportamento do xargs funciona na minha máquina FreeBSD, mas no Linux ou Solaris o comportamento é diferente, então algum outro teste seria necessário.

Como o @ icyrock-com sugere, talvez você queira fazer um mv em vez de um rm , apenas para garantir.

    
por 21.02.2012 / 06:21
0

Não tenho certeza se você pode fazer isso com find , mas aqui está um script de teste que você pode tentar - tente isso em / tmp ou em algum lugar seguro:

# 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

Observe que o acima remove o -mtime +180 para testes, portanto, é necessário ajustar conforme necessário. A saída seria esta:

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

O texto acima excluirá as pastas pai vazias, portanto, se esse for o problema, você pode modificar o while loop para criar apenas um arquivo fictício após cada rm e depois executar outro find de nível superior para excluir estes (nomeie-os de alguma forma para encontrar mais facilmente).

Como nota separada - em vez de excluir, sugiro fazer um mv em algum lugar até que você tenha certeza de que é isso o que deseja. Fazer o backup antes é outra opção.

Espero que isso ajude.

    
por 21.02.2012 / 04:43

Tags