Supprimer des fichiers avec une certaine extension sauf un fichier du terminal

36

Je dois supprimer tous les fichiers avec l'extension .gif, sauf un fichier portant le nom "filename.gif". Quelle est la manière optimale de procéder à cette opération dans un terminal?

La commande rm *.gif supprime tous les fichiers gif, y compris le fichier filename.gif .

    
posée Seth 15.02.2013 - 19:02
la source

4 réponses

66

Voici la solution simple que vous devriez probablement utiliser:

mv filename.gif filename.gif.keep
rm *.gif
mv filename.gif.keep filename.gif

L’extension .keep n’a rien de spécial, ce qui fait que le nom du fichier ne se termine pas temporairement par .gif .

Si vous ne devez pas renommer le fichier (et il y a des situations de script où cela est important):

for X in *.gif; do
    if [ "$X" != "filename.gif" ]; then
        rm "$X"
    fi
done

Ou vous pouvez l'écrire plus court comme ceci:

for X in *.gif; do [ "$X" != "filename.gif" ] && rm "$X"; done

Vous pouvez préférer utiliser find à la place; il est très puissant, vous pourriez le considérer comme plus lisible, et il gère mieux les noms de fichiers étranges avec des caractères comme * .

find . -maxdepth 1 -not -name 'filename.gif' -name '*.gif' -delete

J'ai utilisé l'opérateur -not pour la lisibilité, mais si la conformité de POSIX est importante - si vous Si vous n'utilisez pas GNU find, ou s'il s'agit d'un script que vous avez l'intention de redistribuer à d'autres utilisateurs ou de divers systèmes, utilisez plutôt l'opérateur ! :

find . -maxdepth 1 ! -name 'filename.gif' -name '*.gif' -delete

Une chose pratique à propos de find est que vous pouvez facilement modifier la commande pour ne pas tenir compte de la casse, afin qu'elle trouve et supprime également les fichiers avec les extensions telles que .GIF :

find . -maxdepth 1 -not -name 'filename.gif' -iname '*.gif' -delete

Veuillez noter que j'ai utilisé -iname à la place de -name pour le modèle de recherche *.gif , mais que non ne l'a pas utilisé pour filename.gif . Vraisemblablement, vous savez exactement ce que votre fichier est appelé, et -iname correspondra à une autre majuscule, non seulement dans l'extension , mais n'importe où dans le nom du fichier.

Toutes ces solutions suppriment uniquement les fichiers résidant immédiatement dans le répertoire en cours . Ils ne suppriment pas les fichiers non contenus dans le répertoire en cours et ne suppriment pas les fichiers résidant dans les sous-répertoires du répertoire en cours.

Si vous souhaitez supprimer des fichiers contenus dans le répertoire actuel (y compris dans les sous-répertoires et dans les sous-répertoires de ces sous-répertoires, etc. - fichiers contenus dans le répertoire en cours ou dans ses descendants), utilisez find sans maxdepth -1 :

find . -not -name 'filename.gif' -name '*.gif' -delete

Faites attention à cela!

Vous pouvez également définir d'autres valeurs avec -maxdepth . Par exemple, pour supprimer des fichiers du répertoire en cours et de ses enfants et petits-enfants, mais pas plus profondément:

find . -maxdepth 3 -not -name 'filename.gif' -name '*.gif' -delete

Assurez-vous de ne jamais mettre -delete en premier, avant les autres expressions! Vous verrez que j'ai toujours mis -delete à la fin. Si vous le mettez au début, il sera évalué en premier, et tous les fichiers sous . (y compris les fichiers ne se terminant pas par .gif et les fichiers en profondeur sous-sous-sous ... les répertoires de . ) seraient supprimés!

Pour plus d'informations , consultez les pages de manuel relatives à bash et sh et pour les commandes utilisées dans ces exemples: mv , rm , [ et (en particulier) find .

    
réponse donnée Eliah Kagan 15.02.2013 - 19:33
la source
27

Si vous utilisez bash (le shell par défaut), l'option extglob shell vous permet d'utiliser une syntaxe de correspondance de modèle étendue. Pour l'activer, utilisez la commande intégrée shopt :

shopt -s extglob

(j'inclus cette ligne dans mon fichier .bashrc .)

Entre autres choses, il accorde l’accès à l’opérateur !() , qui correspond à n’importe quel motif ne se trouvant pas à l’intérieur des parens. Pour votre propos:

rm !(filename).gif

Plus d'informations sont disponibles dans man bash sous "Pattern Matching".

    
réponse donnée eswald 16.02.2013 - 00:34
la source
13

Ouvrez un terminal avec Ctrl + Alt + T et tapez:

find . -type f -name "*.gif" -and -not -name "filename.gif" -exec rm -vf {} \;

La différence entre -delete et -exec rm -vf {} \; est qu'avec la deuxième option, vous pourrez voir quels fichiers ont été supprimés, en raison de l'indicateur -v . C'est quelque chose qui ne peut pas être fait avec l'option -delete . ( -name -delete imprimera les noms de fichiers, mais rm avec -v révèle si chaque fichier a été réussi supprimé).

    
réponse donnée efthialex 15.02.2013 - 19:15
la source
1

Il y a la variable GLOBIGNORE . De man bash :

GLOBIGNORE
      A colon-separated list of patterns defining the set of filenames
      to be ignored by pathname expansion.  If a filename matched by a
      pathname expansion pattern also matches one of the  patterns  in
      GLOBIGNORE, it is removed from the list of matches.

Ainsi, une méthode simple consiste à définir GLOBGINORE sur le nom de fichier en question:

$ touch {a,b,c,d}.png
$ echo *.png
a.png b.png c.png d.png
$ GLOBIGNORE=c.png
$ echo *.png
a.png b.png d.png

Alors, dans votre cas:

GLOBIGNORE=filename.gif; rm *.gif

Bien sûr, puisque GLOBIGNORE contient des patterns, vous pouvez l’utiliser lorsque vous souhaitez exclure un pattern:

$ GLOBIGNORE='[a-c].png'; echo *.png
d.png
$ touch bd.png; GLOBIGNORE='?.png'; echo *.png
bd.png

Un avantage (?!) de GLOBIGNORE est que ce paramètre exclut automatiquement . et .. d'être apparié et cela permet à dotglob :

The  GLOBIGNORE shell variable may be used to restrict the set of file‐
names matching a pattern.  If GLOBIGNORE is set, each matching filename
that also matches one of the patterns in GLOBIGNORE is removed from the
list of matches.  The filenames ''.''  and ''..''  are  always  ignored
when  GLOBIGNORE is set and not null.  However, setting GLOBIGNORE to a
non-null value has the effect of enabling the dotglob shell option,  so
all other filenames beginning with a ''.''  will match.  To get the old
behavior of ignoring filenames beginning with a ''.'', make ''.*''  one
of  the  patterns  in  GLOBIGNORE.  The dotglob option is disabled when
GLOBIGNORE is unset.

Donc, un moyen simple de supprimer tous les fichiers et dossiers dans un répertoire:

GLOBIGNORE=.; rm -r *

* correspondra aux noms de fichiers commençant par . , étant donné que GLOBIGNORE enabled dotglob , mais il ne correspondra pas à . ou .. , vous n'affecterez donc pas le répertoire parent .

    
réponse donnée muru 12.03.2016 - 19:45
la source

Lire d'autres questions sur les étiquettes