Exclure un motif de la correspondance globale

54

J'ai plusieurs fichiers avec le même nom de fichier de base. Je voudrais supprimer tous sauf un

foo.org #keep
foo.tex #delete
foo.fls #delete
foo.bib #delete
etc

Si je n'avais pas besoin d'en garder un, je sais que je pourrais en utiliser rm foo.*.

TLDP montre comment^ annuler une correspondance. Par essais et erreurs, j'ai pu constater que

rm foo.*[^org]

fait ce dont j'ai besoin, mais je ne comprends pas vraiment la syntaxe.

De plus, bien que ce ne soit pas une limitation dans mon cas d'utilisation, je pense que ce modèle ignore également foo.oet foo.or. Comment fonctionne ce modèle et à quoi ressemblerait un glob qui ignore tout simplement foo.org ?

Jake
la source
1
En complément de la réponse @glen, il convient de mentionner que rm foo.*[^org]supprime tous les fichiers dont le dernier caractère n'est ni l'un ni l'autre o, ret ne correspond gdonc foo.foopas non plus.
jimmij
Vous utilisez un Regular Expression. Vous devriez faire attention avec vos caractères de regroupement. En utilisant des crochets, vous avez spécifié une classe de caractères, ce qui signifie que vous supprimeriez tous les fichiers ayant une extension avec les lettres o, rou gdans n'importe quel ordre. Utilisez des parenthèses pour créer un groupe et conserver l’ordre des caractères.
M. Mascaro
3
@ jbarker2160 - ce n'est pas vraiment une expression régulière, il est plus communément appelé un glob (ou motif de nom de fichier ), qui est plus ou moins un sous-ensemble d'une expression régulière - voir la section de correspondance de modèle de la page de manuel bash pour plus de détails. Son modèle foo.*[^org]correspond à tout nom de fichier commençant par foo.un ou plusieurs caractères après le point où le dernier caractère n'est pas o, r ou g. Donc, cela correspondrait foo.orb, mais pas foo.orgou foo.orou foo.o. La réponse de GlennJackman montre comment activer les fonctionnalités de correspondance de modèle étendue pour annuler une correspondance.
Johnny

Réponses:

52
shopt -s extglob
echo rm foo.!(org)

C'est "foo". suivi de quelque chose NON "org"

ref: https://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching

Glenn Jackman
la source
J'ai essayé de faire la même chose, mais avec des supports et, apparemment, lorsque vous utilisez des supports, cela ne fonctionne pas
Donato
4
Quelle est la syntaxe pour faire correspondre plusieurs noms de fichiers? dis je veux exclure .org, .png, .txt?
Freedo
@ Freedo @()pour une liste de modèles: stackoverflow.com/a/217208/3779853
phil294
23

En bash, vous pouvez également utiliser GLOBIGNORE="*.org"; rm -i foo*.

Et unset GLOBIGNOREquand c'est fait.

Ce n'est pas vraiment mieux que shopt -s extglob, mais je trouve plus facile de m'en souvenir.

mivk
la source
5
@Ruslan Cela ne fonctionne pas. Vous devriez faire( GLOBIGNORE="*.org"; rm -i foo* )
DBedrenko
3
Notez que si vous souhaitez développer la liste des éléments ignorés, séparez-les par deux points, tels queGLOBIGNORE="*foo*:*bar*"
phyatt
7

Une pipe peut faire?

ls * | grep -v "foo.org" | xargs -I {} echo {}

(Évidemment, vous voudrez peut-être remplacer echo par rm dans la dernière chaîne).

Adobe
la source
Utile si nécessaire en une seule ligne.
bruceskyaus
1
Plus facile à retenir (pour moi, je fais souvent ce genre de choses) et permet de démarrer des traitements plus complexes :)
drevicko
1
ls -1devrait être plus fiable pour s'assurer que tous les fichiers sont traités grepséparément
MichaelChirico
-1

OP était très proche:

rm foo.*[^o][^r][^g]

bien que dans ce cas le *soit inutile.

MrMas
la source
cela échouera à enlever foo.ortetfoo.erg
Adam Katz