Eliminar todos los archivos / directorios excepto un archivo

244

Tengo un directorio que contiene una gran cantidad de archivos. Quiero eliminar todos los archivos excepto file.txt. ¿Cómo hago esto?

Hay demasiados archivos para eliminar los no deseados individualmente y sus nombres son demasiado diversos para usar * para eliminarlos todos excepto este archivo.

Alguien sugirió usar

rm !(file.txt)

Pero no funciona. Vuelve:

Badly placed ()'s 

Mi sistema operativo es Scientific Linux 6.

¿Algunas ideas?

Kantura
fuente
13
mueves el que quieres conservar y luego los otros?
Olivier Dulac
55
@OlivierDulac ¿Somos las dos únicas personas en esta pregunta que no están pensando demasiado en la pregunta?
Shadur
1
@shadur: bueno, me identifico con ellos: los oneliners son atractivos ... ^^
Olivier Dulac
1
Gracias, y sí, estaba buscando una solución de una línea. Lleva demasiado tiempo seguir moviendo archivos, ya que tengo que hacer esto con bastante frecuencia.
Kantura

Respuestas:

288

POSIXY:

find . ! -name 'file.txt' -type f -exec rm -f {} +

eliminará todos los archivos normales (recursivamente, incluidos los ocultos) excepto file.txt. Para eliminar directorios, cambiar -type fa -type dy añadir -rla opción a rm.

En bash, para usar rm -- !(file.txt), debe habilitar extglob :

$ shopt -s extglob 
$ rm -- !(file.txt)

(o llamando bash -O extglob)

Tenga en cuenta que extglobsolo funciona en la bashfamilia de shell Korn. Y el uso rm -- !(file.txt)puede causar un Argument list too longerror.

En zsh, puede usar ^para negar el patrón con el globo extendido habilitado:

$ setopt extendedglob
$ rm -- ^file.txt

o usando la misma sintaxis con kshy bashcon opciones ksh_globy no_bare_glob_qualhabilitado.

Cuonglm
fuente
99
Especificar el directorio es una buena práctica (¿ruta completa en este caso? ¿O tal vez agregar una advertencia aquí de que este comando elimina todos los archivos que comienzan desde el directorio de trabajo actual ?). Por lo general, también escribo cualquier ejemplo con rmas echo rm, y pido a las personas que solo saquen el eco cuando estén realmente seguros de que hará lo que quieran. Aparte de eso, +1 por la respuesta completa
Olivier Dulac
11
Sugeriría en -deletelugar de -exec, más corto y más fácil de recordar
Izkata
66
@Izkata: -deleteno está definido por POSIX.
Cuonglm
55
¿Cómo excluir la lista de archivos?
Meysam
55
@Meysam: vea mi respuesta para una solución que manejará una lista de archivos. De lo contrario, con la findsolución de Gnouc que puede hacer, ! \( -name one_file -o -name two_file \)etc.
mikeserv
112

Otra toma en una dirección diferente (si no hay espacios en los nombres de archivo)

ls | grep -v file.txt | xargs rm

o (funciona incluso si hay espacios en los nombres de archivo)

ls | grep -v file.txt | parallel rm

de man grep:

 -v, --invert-match
          Invert the sense of matching, to select non-matching lines.  (-v is specified by POSIX)
Sebastian
fuente
2
No funcionará si los nombres de archivo tienen un espacio ...
Matteo
1
Ciao @Matteo, también funciona para archivos con espacios, pero necesita rodear el patrón grep con comillas, por ejemplo ls | grep -v "a file with spaces.bin" | xargs rm. Esta es la grepsintaxis normal .
Sebastian
1
@Sebastian El problema no es el greppero rm. rmobtendrá una lista de argumentos separados por espacios. Pruebe touch 'a b'; touch 'c d'; ls | grep -v 'a b' | xargs rm: obtendrá rm: c: No such file or directoryyrm: d: No such file or directory
Matteo
1
Sí, este es un problema común. Ver las opciones -print0en findy -0en xargs. Aquí hay una solución, pero es un poco inconveniente. find . -maxdepth 1 -type f | grep -v 'a b' | tr '\n' '\0' | xargs -0 rm. Por cierto, gnu parallelmaneja esto bien (casi siempre lo uso como un sustituto de xargs:ls | grep -v 'a b' | parallel rm
Sebastian
1
No solo son espacios, son espacios en blanco y líneas nuevas, sino también comillas (comillas simples, comillas dobles y barra invertida) y nombres de archivos que comienzan con -.
Stéphane Chazelas
32

Mantener una copia, eliminar todo, restaurar copia:

{   rm -rf *
    tar -x
} <<TAR
$(tar -c $one_file)
TAR

En una linea:

{ rm -rf *; tar -x; } <<< $(tar -c $one_file)

Pero eso requiere un shell que admita cadenas aquí.

mikeserv
fuente
10
Esto es algo alucinante.
vschum
2
@Derek: vea la edición.
mikeserv
2
Pero si esto se interrumpe a la mitad, o si algo sale mal, el archivo desaparecerá.
kasperd
2
@kasperd - no. Solo si el shell principal muere entre el momento en que se ejecuta rmy tar -x. rmpuede fallar tanto como quiera.
mikeserv
2
¿No es más eficiente moverlo a otro directorio y regresarlo? No necesitamos tratar con el contenido del archivo, solo con su ruta.
leonbloy
23

Todos ustedes están pensando demasiado en esto.

cd ..
mv fulldir/file.txt /tmp/
rm -rf fulldir
mkdir fulldir
mv /tmp/file.txt fulldir/

Hecho.

EDITAR En realidad, más fácil:

cd ..
ln fulldir/file.txt ./
rm -rf fulldir
mkdir -p fulldir
mv file.txt fulldir/
Shadur
fuente
3
Eso es lo mismo que hace mi respuesta. exce [pt no pierde ningún permiso en el directorio.
mikeserv
66
Si es un archivo grande en un sistema de archivos separado de / tmp y está tratando de eliminar todo desde la raíz del sistema de archivos hacia abajo, moverlo a un lugar seguro puede no ser una opción.
Johnny
1
Esta es definitivamente la respuesta más simple.
Ben Liyanage
17

En mi sistema operativo Scientific Linux 6 esto funciona:

shopt -s extglob
rm !(file.txt)

También tengo Debian 32bit instalado en una máquina virtual. Lo anterior no funciona pero lo siguiente sí:

find . -type f ! -name 'file.txt' -delete
Kantura
fuente
1
¿Quiere decir que la findsolución que le di no funcionó?
Cuonglm
"no funcionó" o "no funciona". Sí, su solución de búsqueda también funciona. Gracias.
Kantura
1
¿Puedes hacer más detalles? ¿Cómo "no funcionó? ¿No elimina otros archivos, o eliminó file.txto cualquier otra cosa?"
Dijo el
Quise decir que en el sistema operativo Debian "$ rm! (File.txt)" devuelve "Mal colocado () 's". Así que probé "$ shopt -s extglob", pero me devolvió: "shopt: Comando no encontrado". Luego probé la solución "encontrar". Funciona
Kantura
1
Oh, claro que no funciona. shoptNo es una tcshconstrucción.
Cuonglm
10

Usar en rm !("file.txt")lugar derm !(file.txt)

www.wishinfo.net
fuente
44
Eso no hace absolutamente ninguna diferencia. El problema aquí era que el OP era 1) no usar un shell que admita este formato y 2) incluso en bash, debe habilitarlo con shopt -s extglob. En cualquier caso, citar un nombre de archivo simple como ese no habría hecho ninguna diferencia.
terdon
1
Para mantener solo la carpeta utils do - rm -rf! ("Utils")
James Jithin
7

Solo para dar una respuesta diferente, puede usar el comportamiento predeterminado de rmque no eliminará carpetas:

mkdir tmp && mv file.txt tmp  # create tmp dir and move files there
rm                            # delete all other files
mv tmp/* . && rm -rf tmp      # move all files back and delete tmp dir
Nithin
fuente
1

Creo que este enfoque es muy simple, funciona y no requiere ninguna extensión especial (¡que yo sepa!)

ls --hide=file.txt | xargs rm
2 bits
fuente