¿Cómo eliminar todos los archivos en un directorio excepto algunos?

123

Necesito eliminar todos los archivos en un directorio, pero excluir algunos de ellos. Por ejemplo, en un directorio con los archivos a b c ... z, necesito eliminar todo excepto para uy p. ¿Hay una forma fácil de hacer esto?

Un disparo
fuente
Las respuestas a continuación son mucho mejores, pero puede hacer que los archivos se guarden como de solo lectura, eliminarlos y luego volver a cambiarlos a sus permisos originales (siempre y cuando no use rm -f). Tendría que saber qué permisos restaurar y tendría que saber que no se necesita acceso de escritura a ellos durante el proceso. Es por eso que las otras respuestas son mejores.
Joe
1
Si también desea eliminar archivos ocultos, ejecute shopt -s dotglobantes de ejecutar rm (...).

Respuestas:

108

Lo que hago en esos casos es escribir

rm *

Luego presiono Ctrl+ X, *para expandir * a todos los nombres de archivo visibles.

Luego puedo eliminar los dos archivos que me gusta mantener de la lista y finalmente ejecutar la línea de comando.

Der Hochstapler
fuente
25
Supongo que esto funciona solo mientras la lista de archivos que se *expande también no sea demasiado larga. : -}
Frerich Raabe
99
Esc seguido de * también expandirá el "*".
slowpoison el
2
@SantoshKumar: Eso no tiene sentido para mí. La expansión siempre funcionará, no depende de qué comando desea usar después.
Der Hochstapler
2
@OliverSalzburg Lo siento, la combinación es un poco confusa. Creo que deberías escribir como Ctrl+ Shift+ x+*
Santosh Kumar
2
@SantoshKumar: Pero esa no es la combinación.
Der Hochstapler
143

Para rmtodos, pero u,pen bash solo escriba:

rm !(u|p)

Esto requiere que se configure la siguiente opción:

shopt -s extglob

Ver más: glob - Greg's Wiki

chispa
fuente
1
debes tener activo 'extglobbing': shopt -s extglob
sparkie
18
Necesitas shopt -s extglob, @Ashot. Además, son solo archivos, no directorios, por eso he eliminado las -rfopciones en su comando.
slhck
44
Si necesita excluir un archivo de una selección de archivos, intente lo siguiente: rm !(index).html. Esto eliminará todos los archivos que terminen en ".html" con la excepción de "index.html".
mzuther
71

Puedes usar find

find . ! -name u ! -name p -maxdepth 1 -type f -delete
  • ! niega la siguiente expresión
  • -name especifica un nombre de archivo
  • -maxdepth 1hará que find procese solo el directorio especificado ( findpor defecto atraviesa directorios)
  • -type f procesará solo archivos (y no, por ejemplo, directorios)
  • -delete borrará los archivos

Luego puede ajustar las condiciones mirando la página de manual de find

Actualizar

  • Tenga en cuenta que el orden de los elementos de las expresiones es significativo (consulte la documentación)
  • Pruebe su comando primero usando en -printlugar de-delete

    find . ! -name u ! -name p -maxdepth 1 -type f -print
Matteo
fuente
55
El orden de los predicados es crítico aquí. Si uno lo pone -deletejusto después ., será un desastre (eliminará todos los archivos en CWD)
Michał Šrajer
Esto podría escribirse de manera más compacta comofind . -maxdepth 1 -type f -name '[^up]' -delete
kojiro
44
@kojiro sí, pero solo para archivos que son solo una letra. Con nombres más complejos, la expresión regular podría ser un desastre.
Matteo
2
findes mi mejor amigo, especialmente cuando hay demasiados archivos para bloquear
Terence Johnson el
43

Sencillo:

mvlos archivos que desea en un directorio superior, rmel directorio y luego mvlos devuelve.

usuario176581
fuente
13
Por supuesto, muévalos a un directorio más alto. Intenta no moverlos a un subdirectorio que estás eliminando ...
Konerak
@Konerak: rmsin -rno eliminará subdirectorios.
reinierpost
11
Esto sobrescribirá los archivos con el mismo nombre en el directorio de destino
Matteo
77
Estoy rechazando esto porque, aunque puede ser útil, tampoco es atómico y elimina eficazmente todos los archivos del directorio durante un corto período de tiempo; esto no sería aceptable si, por ejemplo, los archivos se comparten en la red.
sam hocevar
15

Algo similar a esta respuesta, pero no se necesitan opciones especiales, por lo que sé, la siguiente es una funcionalidad "antigua" compatible con cualquier shell (vagamente) / bin / sh que se parezca (por ejemplo, bash, zsh, ksh, etc.)

rm [^up]
hlovdal
fuente
2
Esto funciona para los nombres de archivo 1-char. Para nombres más largos, la respuesta de sparkie es mejor.
Glenn Jackman
3
¿Qué estaría mal con rm [^up]*? Hago cosas similares con bastante frecuencia.
un CVn
3
@ MichaelKjörling: esto eliminaría todos los archivos que comienzan con u o p, no solo aquellos con los nombres u y p. Creo que el OP (@Ashot) significaba el az yu, p, etc. simbólicamente y no literalmente.
Sudipta Chatterjee
44
@HobbesofCalvin Eso eliminaría todos los archivos que no comiencen con uop , no los que comiencen con ellos.
rjmunro
@rjmunro - ¡gracias, me perdí esa! :)
Sudipta Chatterjee
11

Haciéndolo sin encontrar:

ls | grep -v '(u|p)' | xargs rm

(Editar: "u" y "v", como en otros lugares aquí, se están utilizando como versiones genéricas de expresiones regulares completas. Obviamente, querrás tener cuidado de anclar tus expresiones regulares para evitar emparejar demasiadas cosas).

Definitivamente vas a querer un script si vas a hacer mucho de esto, como han sugerido otros.

tquid
fuente
grep no manejará expresiones regulares extendidas por defecto: use -Eoegrep
Matteo
2
esto excluirá cualquier archivo que contenga un uo unp
Matteo
@ Matteo No, no lo hará. El grep no está grepping los archivos, está grepping la salida del comando ls. Estás pensando en algo como grep -L (u|p)' * | xargs rmdonde -Lsignifica listar nombres de archivos que no contienen una coincidencia.
rjmunro
44
Ah, te refieres a cualquier archivo cuyo nombre contenga uo p, no cualquier archivo que contenga a uo a p. Eso es correcto. Puede corregir mediante el usoegrep -v '^(u|p)$'
rjmunro
1
¡Aquí está eliminar todo excepto estos partidos! ls | grep -v 'vuze\|progs' | xargs rm -rf
Nick
6

En zsh:

setopt extended_glob  # probably in your .zshrc

entonces

rm ^(u|p)

o

rm *~(u|p)

La segunda funcionará incluso si usted tiene ^en $histcharsla sustitución de la historia, y por supuesto se puede poner un pegote arbitraria antes de la ~.

billar
fuente
5

GLOBIGNORE toma una lista separada por dos puntos

GLOBIGNORE=u:p
rm *
W_Whalley
fuente
12
Esto no funciona en mi shell (GNU bash 4.1.5 (1)). ¡Asegúrese de probarlo primero con algo un poco menos dañinorm o en un directorio de prueba!
un CVn
3

En la era de los disquetes, tenía un ejecutable de dos llamado "Excepto" que movería las cosas del directorio actual temporalmente y ejecutaría un comando, por lo que podría decir:

excepto * .txt del *. *

para eliminar todo menos tus archivos de texto.

Esto sería algo bastante trivial para implementar como un script de shell y si este es el tipo de cosas que es probable que haga más de dos veces, parece que sería una buena idea.

Bill K
fuente
2
Me recordó lo mismo. Pero salir temporalmente de la carpeta puede no ser una buena idea en la era de la multitarea :)
Sedat Kapanoglu
3
 find . -maxdepth 1 ! -name "u" ! -name "p" -type f -exec rm -rf {} \;

Esto eliminará todos los archivos excepto U y P en Unix

usuario1803687
fuente
2

Para aquellos que prefieren especificar patrones de exclusión complejos arbitrarios (que abarcan todos los nombres de archivos afectados) en un estilo completo de expresiones regulares emacs, posix-awk o posix-extended (consulte la página del manual de Find), recomendaría este. Excluye uy pen el directorio actual en este ejemplo. Esto puede ser útil para los scripts.

find -regextype posix-awk ! -regex './(u|p)' -print0 | xargs -0 rm -rf
chispa
fuente
Debe especificar un directorio antes de la expresión (`find. -Regextype ...).
Matteo
-regextypesolo funcionará en versiones de GNU
Matteo
no - mi versión find (Debian Squeeze) no definitivamente no requiere un directorio explícito antes de la expresión si el directorio actual debe utilizarse
sparkie
@sparke: esto simplemente funciona en implementaciones de GNU
Matteo
@sparkie: no definir el directorio (primer parámetro) para findes una extensión de findcomando GNU . Lo mismo se aplica para la -regextypeopción. Además, su comando también eliminará archivos en subdirectorios, mientras que la pregunta original claramente se refería a los archivos en un directorio.
Mikko Rantalainen
1

Yo siempre uso:

rm [a-o,q-t,v-z]*

Esto le permitirá definir qué tan granular desea hacer. Entonces, si desea eliminar los archivos a través de o y Z, puede usar:

rm [a-o,z]*
J baron
fuente
1

Otra versión más que usa xargs:

ls -1 | grep -v do_not_delete | xargs -I files rm "files"

Tenga en cuenta que xargs -Ies necesario para manejar los nombres de archivos, incluidos los espacios correctamente.

Sebhofer
fuente
1

Aún otra:

for FILE in ./*; do if [[ $FILE != ./u* ]] || [[ $FILE != ./p* ]];then rm $FILE; fi; done;

Es un poco largo y no sé si podría convertirlo fácilmente en una función que pudiera acomodar fácilmente un número arbitrario de argumentos, pero funciona bien.

Y es pura bondad.

dylnmc
fuente
1

Aquí hay otra variante. Puedes escribir:

rm -i *

o:

rm --interactive *

Por rmlo tanto, le pedirá que confirme la eliminación de cada archivo.

idzikovsky
fuente
1

Utilizar:

find . -type f ! -name 'u' ! -name 'p' ! -name '*.ext' -delete
find . -type d ! -name 'u' ! -name 'p' ! -name '*.ext' -delete

para eliminar todos los archivos, incluidos los directorios, excepto los archivos u, p y .ext.

Renzo Fabián
fuente
0

Una forma simple que es difícil de arruinar: supongamos que desea eliminar todo excepto * .pdf:

mkdir tmp
mv *.pdf tmp
rm *
mv tmp/* .
rm -r tmp
talloaktrees
fuente