Como posso excluir arquivos numerados em um determinado intervalo?


16

Eu tenho folderAque tem alguns arquivos com uma sequência numérica começando com a_000000. O que eu quero fazer é excluir arquivos a partir de um número específico: digamos a_000750até o final dos arquivos folderA. Alguém poderia aconselhar como fazer isso usando o shell script?


Posso assumir que todos esses nomes de arquivos têm sufixos de 6 dígitos?
muru 27/09/14

sim, eles são :) eles começam a partir a_000000 até algum número
Tak

5
rm a_000[89]* a_0007[5-9]*?
Rinzwind 27/09/14

@Rinzwind você poderia explicar este comando?
27414 Tak

2
@ user1460166 a_000[89]*inclui todos os arquivos que começam com a_0008ou a_0009e a_0007[5-9]*incluem todos os arquivos que começam com a_0007e, em seguida, contêm um número entre 5 e 9, seguido por qualquer coisa.
muru 27/09/14

Respostas:


35

Supondo que você saiba ou possa adivinhar o final do intervalo, você pode usar expansões de chaves :

rm a_{000750..000850}

O item acima excluirá os 101 arquivos entre a_000750 e a_000850 inclusive (e reclamará dos nomes de arquivos que se referem a arquivos inexistentes). Se você tiver muitos arquivos para isso, use find:

find . -name 'a_*' | while read file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Aqui, o findsimplesmente lista todos os arquivos correspondentes a_*. A lista é passada para um whileloop em que cada nome de arquivo é lido na variável $file. Em seguida, usando os recursos de manipulação de seqüência de caracteres do bash , se a parte numérica (localizar imprime arquivos como ./file, portanto, ${file#./a_}imprime apenas o número) for 000750maior ou maior, o arquivo será excluído. O -vestá lá para que você possa ver quais arquivos foram removidos.

Observe que o acima pressupõe nomes de arquivos sãos. Se seus nomes puderem ter espaços, novas linhas ou outros caracteres estranhos, use isso:

find . -name 'a_*' -print0 | while IFS= read -rd '' file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Por que evitar [[?
muru 27/09/14

11
@muru por que usá-lo? [[não simplifica as coisas aqui, [[ "${file#./a_}" > 000749 ]]por exemplo, nem a torna mais curta. Eu não gosto de usar sintaxe desnecessária e essa funcionará mesmo em shells mais simples dash.
terdon 27/09/14

Porque [[lida melhor com espaços e estranhezas (eu também não ligo muito >).
muru 27/09/14

11
@uru sim, mas [é bom se você citar a variável como eu tenho, funciona em muito mais conchas e é mais simples.
terdon 27/09/14

Se você insiste. Não é problema meu.
muru 27/09/14

3

Você poderia fazer algo assim:

find . -regextype posix-extended -iregex './a_[0-9]{6}' -execdir bash -c '[[ ${1##./a_} > 000750 ]] && echo $1' "removing: " {} \;

Ou:

find . -regextype posix-extended -iregex './a_[0-9]{6}' | sort | sed '0,/000750/d' | xargs echo

O primeiro método assume um prefixo fixo, retira-o e verifica o valor.

O segundo método assume um sufixo de tamanho fixo (e um prefixo fixo comum) e se baseia nesse fato; e que, embora 201venha antes 31em lexicograficamente, não antes 031.

Teste isso com o echocomando e, quando tiver certeza de que ele lista os arquivos corretos, use-o rm.


nenhum deles está funcionando: /
Tak

@ user1460166 ah, isso provavelmente se deve à correspondência de regex. Vou atualizá-lo.
muru 27/09/14

Ainda não funciona. btw, os arquivos são .png :)
Tak

@ user1460166 você pode dizer como não está funcionando?
muru 27/09/14

Eu abrir o terminal, cd para a pasta, em seguida, copiar a sua linha e colá-lo, mas os arquivos não são excluídos
Tak

0

Solução shell POSIX

A primeira solução do terdon depende da expansão de chaves, que é uma propriedade de bashe ksh, no entanto, não pode ser usada no /bin/shshell padrão , no qual o Ubuntu está vinculado /bin/dash.

Nos casos em que você precisa confiar /bin/shna portabilidade de seus scripts, geralmente há duas maneiras de abordar isso. Um seria via globbing. Apenas cd folderAe de lá corra rm a_*. Por outro lado, seria implementar uma alternativa para loop no estilo C usando while <CONDITION>;do ...donena linguagem shell e formatar os números com printf:

$ sh -c 'i=0;while [ $i -le 750 ]; do filename=$(printf "a_%06d" $i);echo "$filename";i=$((i+1)) ;done'

Observe que aqui eu uso echo. Substitua echo "$filename"por rm ./"$filename"ou rm -- "$filename"quando estiver pronto para excluir os arquivos. Observe também que isso deve ser realizado quando você já estiver cdno diretório desejado.

(ab) usando awk

O awk, sendo uma linguagem C agradável, pode nos ajudar de duas maneiras: (1) podemos gerar nomes de arquivos com loop for e formatá-los via sprintffunção e (2) excluir os arquivos por system()comando, o que passará nosso nome de arquivo e rmcomando gerados para /bin/sh:

awk 'BEGIN{for(i=0;i<=750;i++){filename=sprintf("a_%06d",i);system("rm "filename);} }'

Perl

Continuando com a idéia de abordagem portátil onde "geramos" nomes de arquivos, podemos fazer o mesmo no Perl:

perl -le 'for(0..750){$fd=sprintf("a_%06d",$_);unlink($fd)}'

0

Tão simples quanto

rm partialfilename* -f

No seu exemplo é

rm a_00075* -f

11
Desculpe dizer, mas isso não é um intervalo, esses são todos os arquivos começando com a_00075...
Fabby

11
* é um curinga, o OP está procurando uma resposta sobre como excluir uma GAMA de coisas ... por exemplo, se você tivesse arquivos de 1 a 100 e desejasse excluir # 41 a # 75 #
Joshua Besneatte
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.