Excluir un patrón de la coincidencia global

54

Tengo varios archivos con el mismo nombre de archivo base. Me gustaría eliminar todos menos uno

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

Si no necesito conservar uno, sé que podría usarlo rm foo.*.

TLDP demuestra ^negar un partido. A través de prueba y error, pude encontrar que

rm foo.*[^org]

hace lo que necesito, pero realmente no entiendo la sintaxis.

Además, aunque no es una limitación en mi caso de uso, creo que este patrón también ignora foo.oy foo.or. ¿Cómo funciona este patrón, y lo que sería un pegote que ignora solamente foo.org parece?

jake
fuente
1
Como complemento a la respuesta @glen vale la pena mencionar que rm foo.*[^org]elimina todos los archivos de los cuales último carácter es ni o, ro g, por lo que foo.foono corresponde a ninguno.
jimmij
Estás usando a Regular Expression. Debes tener cuidado con tus caracteres de agrupación. Al usar corchetes, ha especificado una clase de caracteres que significa que eliminaría cualquier archivo que tuviera una extensión con las letras o, ro gen cualquier orden. Use paréntesis para crear un grupo y preservar el orden de los caracteres.
Sr. Mascaro
3
@ jbarker2160: esa no es realmente una expresión regular, más comúnmente se llama glob (o patrón de nombre de archivo ), que es más o menos un subconjunto de una expresión regular; consulte la sección de coincidencia de patrones de la página de manual de bash para obtener más detalles. Su patrón foo.*[^org]coincidirá con cualquier nombre de archivo que comience con foo.uno o más caracteres después del punto donde el último carácter no sea o, r o g. Por lo tanto, coincidiría foo.orb, pero no foo.orgo foo.oro foo.o. La respuesta de GlennJackman muestra cómo habilitar las características extendidas de coincidencia de patrones para negar una coincidencia.
Johnny

Respuestas:

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

Esto es "tonto". seguido de cualquier cosa que NO sea "org"

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

Glenn Jackman
fuente
Traté de hacer lo mismo pero con corchetes y aparentemente cuando uso corchetes no funciona
Donato
44
¿Cuál es la sintaxis para coincidir con varios nombres de archivo? decir que quiero excluir .org, .png, .txt?
Freedo
@Freedo @()para una lista de patrones: stackoverflow.com/a/217208/3779853
phil294
23

En bash, también puedes usar GLOBIGNORE="*.org"; rm -i foo*.

Y unset GLOBIGNOREcuando termine.

No es realmente mejor que shopt -s extglob, pero me resulta más fácil de recordar.

mivk
fuente
55
@Ruslan Eso no funciona. Deberías hacerlo( GLOBIGNORE="*.org"; rm -i foo* )
DBedrenko
3
Tenga en cuenta que si desea expandir la lista de ignorados, separe con dos puntos, comoGLOBIGNORE="*foo*:*bar*"
phyatt
7

Una pipa puede hacer?

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

(obviamente, es posible que desee reemplazar echo con rm en la última cadena).

Adobe
fuente
Útil si es necesario en una sola línea.
bruceskyaus
1
Más fácil de recordar (para mí, hago ese tipo de cosas a menudo) y permite un procesamiento más complejo para arrancar :)
drevicko
1
ls -1debería ser más confiable para garantizar que todos los archivos se manejen por grepseparado
MichaelChirico
-1

OP estuvo muy cerca:

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

aunque en este caso *es innecesario.

MrMas
fuente
esto no se eliminará foo.ortyfoo.erg
Adam Katz