Exclui todos os arquivos em um diretório cujo nome não corresponda a uma linha em uma lista de arquivos

9

Eu tenho um diretório com mais de 1.000 arquivos. Em um arquivo de texto, tenho cerca de 50 nomes de arquivos, um por linha. Eu gostaria de excluir todos os arquivos no diretório cujos nomes de arquivos não correspondem a uma entrada na lista. Qual é a melhor forma de fazer isso? Eu iniciei um script de shell, mas não consegui determinar o comando adequado para determinar se o nome do arquivo está na lista. Obrigado.

    
por Nathan 30.04.2014 / 14:55

7 respostas

8

Eu percebo que qualquer pergunta sobre como excluir arquivos deve ser feita com muito cuidado. Minha primeira resposta foi muito apressada. Eu não aceitei o fato de que a lista de arquivos poderia ser malformada para ser usada com o egrep. Eu editei a resposta para reduzir esse risco.

Isso deve funcionar para os arquivos que não têm espaço no nome:

Primeiro, reconstrua sua lista de arquivos para ter certeza de corresponder ao nome exato do arquivo:

sed -e 's,^,^,' -e 's,$,$,'  filelist  > newfilelist 

construa os comandos rm

cd your_directory
ls | egrep -vf newfilelist   | xargs -n 1 echo rm  >  rmscript

Verifique se a script rm combina com você (você pode fazer isso com "vim" ou "less").
Em seguida, execute a ação:

sh -x rmscript

Se os arquivos tiverem espaços em seus nomes (se os arquivos tiverem o " no nome, isso não funcionará):

ls | egrep -vf newfilelist  | sed 's,^\(.*\)$,rm "",' > rmscript

é claro que a lista de arquivos não deve estar no mesmo diretório!

EDITADO:

A lista de arquivos do Nathan continha nomes que correspondiam a todos os arquivos no diretório (como "html" corresponde a "bob.html"). Portanto, nada foi excluído porque egrep -vf absorveu todo o fluxo. Eu adicionei um comando para colocar um "^" e um "$" em torno de cada nome de arquivo. Eu tive sorte aqui que a lista de arquivos de Nathan estava correta. Teria sido formatado no DOS com linhas CR-LF terminadas ou com espaços adicionais, nenhum arquivo teria sido preservado pelo egrep e todos foram excluídos.

    
por 30.04.2014 / 15:27
1

Pré-construa os argumentos para find :

{
  read -r
  keep=( -name "$REPLY" ) # no '-o' before the first one.
  while read -r; do
    keep+=( -o -name "$REPLY" )
  done
} < file_list.txt
find . -type f ! \( "${keep[@]}" \) -exec echo rm {} +

Use as partes echo para ver o que seria construído. Remova as partes echo para executá-lo.

Atualização: demonstração:

##
# Demonstrate what files exist for testing.
# Show their whitespace:
~/foo $ printf '"%s"\n' *
" op"
" qr"
"abc"
"def"
"gh "
"ij "
"k l"
"keep"
"m n"

##
# Show the contents of the "keep" file,
# Including its whitespace:
~/foo $ cat -e keep
keep$
abc$
gh $
k l$
 op$

##
# Execute the script:
~/foo $ { read -r; keep=( -name "$REPLY" ); while read -r ; do keep+=( -o -name "$REPLY" ); done } < keep
~/foo $ find . -type f ! \( "${keep[@]}" \) -exec rm {} +

##
# Show what files remain:
~/foo $ printf '"%s"\n' *
" op"
"abc"
"gh "
"k l"
"keep"
    
por 30.04.2014 / 16:55
1

com zsh :

mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Ele lê as linhas de filelist em uma matriz e, em seguida, usa qualificadores de glob / e string para glob / selecionar apenas os nomes de arquivo não presentes na matriz: o . seleciona apenas arquivos regulares (adicione D se sua lista contiver dotfiles) e o ^e_'expression'_ negado seleciona apenas aqueles para os quais a expressão retorna false, ou seja, se o nome ( $REPLY ) não for um elemento da matriz

Se estiver satisfeito com o resultado, substitua print -rl por rm para remover os arquivos:

rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Para selecionar & remova arquivos recursivamente, use o */** glob com o modificador glob ${REPLY:t} :

rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)
    
por 28.01.2016 / 03:27
0

Se você colocar o conteúdo do diretório em um arquivo como este:

cd <somedirectory>
ls >> filelist

Abra a lista de arquivos com um editor de texto e remova todos os arquivos, exceto os que VOCÊ QUER EXCLUIR . Isso é em negrito porque é a abordagem oposta à resposta acima

Tente isto:

while read p || [[ -n $p ]]; 
echo $p
done < filelist

Se você vir sua lista de arquivos de saída para a tela, substitua echo por rm -v , da seguinte forma:

while read p || [[ -n $p ]]; 
rm -v $p
done < filelist
    
por 30.04.2014 / 16:41
0

Execute o script abaixo.

  1. Inicialmente eu estou encontrando todos os arquivos que estão presentes dentro do diretório e armazenar a saída para outro arquivo all_files .
  2. Temos um arquivo com a lista de arquivos que devem NÃO ser excluído ( not_to_be_deleted_files ).
  3. Estou adicionando os nomes dos arquivos not_to_be_deleted_files e files_to_be_deleted ao final de not_to_be_deleted_files como nós precisa desses 2 arquivos.
  4. Agora, estou encontrando os arquivos que precisam ser excluídos usando o linux Comando join e redirecionando a saída para files_to_be_deleted arquivo.
  5. Agora, no loop while final eu estou lendo todos os nomes de arquivo em files_to_be_deleted e removendo os arquivos mencionados nesse arquivo nome.

O script é como abaixo.

find /home/username/directory -type f | sed 's/.*\///' > all_files
echo all_files >> not_to_be_deleted_files
echo not_to_be_deleted_files >> not_to_be_deleted_files
echo files_to_be_deleted >> not_to_be_deleted_files
join -v 1 <(sort all_files_listed) <(sort files_not_to_be_deleted) >   files_to_be_deleted
while read file
rm  "$file"
done < files_to_be_deleted

P.S : Provavelmente, se você desejar que isso seja salvo como um script e executá-lo, adicione o nome do script também usando echo scriptname >> not_to_be_deleted_files .

Embora não seja obrigatório, prefiro fazê-lo porque não haverá arrependimentos mais tarde. Eu testei para um pequeno conjunto de arquivos e funcionou no meu sistema. No entanto, se quiser ter certeza, tente primeiro um diretório test e remova os arquivos no diretório original.

    
por 30.04.2014 / 16:58
0
  • Use a lista como fonte para mover todos os arquivos da lista para um diretório de salvamento novo, novo e vazio.
  • Compare o número de arquivos na lista e o número de arquivos salvos.
  • Se ambos combinarem, exclua todos os arquivos não salvos com seu método favorito.
  • Mova os arquivos salvos de volta.
por 08.03.2018 / 17:06
0

Eu fui para uma abordagem mais segura e muito mais rápida porque eu tinha 18.000 arquivos na lista! Eu precisava limpar imagens em uma grande instalação do Drupal.

Excluir todos os arquivos que não estão na lista é o mesmo que manter apenas aqueles que estão na lista. Então, decidi copiar os arquivos da lista para outro local, mas copiar 20 GB de arquivos ocuparia muito espaço e seria muito lento também. Então, o truque é copiar os arquivos como hardlinks , usando a opção -l de cp . Isso ocupa quase nenhum espaço e é muito rápido. Além disso, como eu precisava preservar a estrutura de diretórios, usei a opção --parents .

Aqui está um trecho da minha lista de arquivos:

1px.png
misc/feed.png
modules/file/icons/x-office-presentation.png
modules/file/icons/x-office-spreadsheet.png
newsletter.png
sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png
sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.png
sites/default/files/009313_PwC_banner_CBS_Observer_180x246px.jpg

Assim, uma linha de exemplo seria, com temp sendo o destino:

cp -l --parents 'misc/feed.png' temp

Isso criará essa estrutura:

temp
  misc
    feed.png

Observe que o destino deve estar no mesmo sistema de arquivos que a fonte de hardlinks para funcionar.

O próximo passo é construir o script:

sed -e "s,^,cp -l --parents '," -e "s,$,' /some/where/temp," filelist > newfilelist

Agora, presumindo que você já criou o diretório vazio / algum / onde / temp, você pode copiar os arquivos assim:

sh newfilelist 2> missing_files

Observe como os erros acabam em missing_files . A vantagem adicional dessa abordagem é que você obterá uma lista de arquivos da lista original que realmente não existe !

Depois de executar o script, temp conterá apenas os arquivos que estão na lista de arquivos, mas sem excluir nada e sem ocupar espaço adicional. Se você estiver satisfeito com o resultado, você pode excluir todos os arquivos originais, incluindo as subpastas.

Por fim, mova os arquivos e pastas de temp de volta para o local original.

Para os 18.000 arquivos, levou apenas alguns segundos.

    
por 10.11.2018 / 14:32

Tags