web-dev-qa-db-fra.com

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

J'ai folderA qui contient des fichiers avec une séquence numérique commençant par a_000000. Ce que je veux faire, c'est supprimer les fichiers à partir d'un numéro spécifique: disons a_000750 jusqu'à la fin des fichiers de ce folderA. Quelqu'un pourrait-il s'il vous plaît indiquer comment faire cela en utilisant un script Shell?

16
Tak

En supposant que vous sachiez ou que vous puissiez deviner la fin de la plage, vous pourriez utiliser expansions d'accolades :

rm a_{000750..000850}

Ce qui précède supprimera les 101 fichiers compris entre a_000750 et a_000850 inclus (et se plaindra des noms de fichiers faisant référence à des fichiers non existants). 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, find liste simplement tous les fichiers correspondant à a_*. La liste est transmise à une boucle while où chaque nom de fichier est lu dans la variable $file. Ensuite, en utilisant les fonctionnalités manipulation de chaînes de bash, si la partie numérique (find imprime des fichiers sous la forme ./file, afin que ${file#./a_} imprime le nombre uniquement) est égale à 000750 ou plus, le fichier est supprimé. Le -v est juste là pour que vous puissiez voir quels fichiers ont été supprimés.

Notez que ce qui précède suppose des noms de fichiers sains. Si vos noms peuvent avoir des espaces, des nouvelles lignes ou d'autres caractères étranges, utilisez ceci à la place:

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

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, bien que 201 vienne avant 31 dans le lexicographe, il n'en a pas avant 031.

Testez cela avec la commande echo et, une fois que vous êtes sûr qu'elle répertorie les fichiers corrects, utilisez plutôt rm.

3
muru

Solution POSIX Shell

la première solution de terdon s'appuie sur le développement d'accolade, qui est une propriété de bash et ksh, mais ne peut pas être utilisé dans le shell standard /bin/sh qui, sur Ubuntu, est lié symboliquement à /bin/dash.

Dans les cas où vous devez utiliser /bin/sh pour la portabilité de vos scripts, il existe généralement deux façons de procéder. On serait via globbing. Juste cd folderA et à partir de là, lancez rm a_*. L’autre solution consisterait à implémenter une alternative de style C pour une boucle utilisant while <CONDITION>;do ...done en langage Shell et à 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 que j'utilise ici 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à cded dans le répertoire souhaité.

(ab) en utilisant awk

Awk étant un langage similaire à C, peut nous aider de deux manières: (1) nous pouvons générer des noms de fichiers avec une boucle for et les formater via la fonction sprintf, et (2) supprimer ces fichiers via la commande system(), qui transmettra notre nom de fichier généré et rm command to /bin/sh:

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

Perl

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

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