Comment supprimer des fichiers numérotés dans une plage donnée?

16

J'ai folderAqui a quelques fichiers avec une séquence de numéros commençant par a_000000. Ce que je veux faire, c'est supprimer des fichiers à partir d'un numéro spécifique: disons a_000750jusqu'à la fin des fichiers folderA. Quelqu'un pourrait-il s'il vous plaît indiquer comment faire cela en utilisant un script shell?

Tak
la source
Puis-je supposer que tous ces noms de fichiers ont des suffixes à 6 chiffres?
muru
oui ils le sont :) ils partent de a_000000 jusqu'à un certain nombre
Tak
5
rm a_000[89]* a_0007[5-9]*?
Rinzwind
@Rinzwind pourriez-vous s'il vous plaît expliquer cette commande?
Tak
2
@ user1460166 a_000[89]*inclut chaque fichier commençant par a_0008ou a_0009, et a_0007[5-9]*inclut chaque fichier commençant par a_0007puis contenant un nombre compris entre 5 et 9, suivi de tout.
muru

Réponses:

35

En supposant que vous connaissez ou pouvez deviner la fin de la plage, vous pouvez utiliser des extensions d'accolade :

rm a_{000750..000850}

Ce qui précède supprimera les 101 fichiers entre a_000750 et a_000850 inclus (et se plaindra des noms de fichiers qui font référence à des fichiers inexistants). Si vous avez trop de fichiers pour cela, utilisez find:

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

Ici, le findrépertorie simplement tous les fichiers correspondants a_*. La liste est passée à une whileboucle où chaque nom de fichier est lu dans la variable $file. Ensuite, en utilisant les fonctionnalités de manipulation de chaînes de bash , si la partie numérique (find imprime les fichiers en tant que ./file, donc ${file#./a_}imprime le nombre uniquement) est 000750ou plus, le fichier est supprimé. Le -vest juste là pour que vous puissiez voir quels fichiers ont été supprimés.

Notez que ce qui précède suppose des noms de fichier sensés. Si vos noms peuvent avoir des espaces, des retours à la ligne ou d'autres caractères étranges, utilisez-les à la place:

find . -name 'a_*' -print0 | while IFS= read -rd '' file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done
terdon
la source
Pourquoi éviter [[?
muru
1
@muru pourquoi l'utiliser? [[ne simplifie pas les choses ici [[ "${file#./a_}" > 000749 ]]par exemple, ne les raccourcit même pas. Je n'aime pas utiliser une syntaxe inutile et celle-ci fonctionnera même dans des shells plus simples comme dash.
terdon
Parce que [[gère mieux les espaces et les bizarreries (je m'en fous beaucoup >non plus).
muru
1
@muru oui, mais [ça va si vous citez la variable comme moi, fonctionne sur beaucoup plus de shells et est plus simple.
terdon
Si vous insistez. Pas mon problème.
muru
3

Vous pouvez faire quelque chose comme ça:

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

La première méthode suppose un préfixe fixe, le supprime et vérifie la valeur.

La deuxième méthode suppose un suffixe de longueur fixe (et un préfixe fixe commun) et s'appuie sur ce fait; et que, tout en201 qu'avant 31en lexicographiquement, il ne le fait pas avant031 .

Testez-le avec la echocommande, et une fois que vous êtes sûr qu'il répertorie les fichiers corrects, utilisez rmplutôt.

muru
la source
aucun d'entre eux ne fonctionne: /
Tak
@ user1460166 ah, c'est probablement dû à la correspondance d'expressions régulières. Je vais le mettre à jour.
muru
ne fonctionne toujours pas. btw, les fichiers sont .png :)
Tak
@ user1460166 pouvez-vous dire comment cela ne fonctionne pas?
muru
J'ouvre le terminal, cd dans le dossier, puis copiez votre ligne et collez-le, mais les fichiers ne sont pas supprimés
Tak
0

Solution shell POSIX

La première solution de terdon repose sur l'expansion des accolades, qui est une propriété de bashet ksh, cependant, elle ne peut pas être utilisée dans le /bin/shshell standard , qui sur Ubuntu est lié à/bin/dash .

Dans les cas où vous devez vous fier /bin/shà la portabilité de vos scripts, il y a généralement deux façons d'aborder cela. On serait via globbing. Juste cd folderAet à partir de là, courez rm a_*. L'autre façon, serait d'implémenter une alternative de style C pour les boucles en utilisant while <CONDITION>;do ...doneen langage shell et de formater les nombres avec printf:

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

Notez qu'ici j'utilise echo. Remplacez echo "$filename"par rm ./"$filename"ou rm -- "$filename"lorsque vous êtes prêt à supprimer les fichiers. Notez également que cela doit être effectué lorsque vous avez déjàcd édité dans le répertoire souhaité.

(ab) en utilisant awk

Awk étant un joli langage de type C peut nous aider de deux manières: (1) nous pouvons générer des noms de fichiers avec for-loop et les formater via une sprintffonction, et (2) supprimer lesdits fichiers via une system()commande, qui passera notre nom de fichier généré et la rmcommande à /bin/sh:

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

Perl

Poursuivant avec l'idée d'une approche portable où nous "générons" des noms de fichiers, nous pouvons faire de même en Perl:

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

Aussi simple que

rm partialfilename* -f

Dans votre exemple, c'est

rm a_00075* -f
Vitaly Dubyna
la source
1
Désolé de le dire, mais ce n'est pas une plage, ce sont tous des fichiers commençant par a_00075...
Fabby
1
* est un caractère générique, OP cherche une réponse sur la façon de supprimer une gamme de choses ... par exemple, si vous aviez des fichiers 1 à 100 et que vous vouliez supprimer # 41 à # 75
Joshua Besneatte