Hay 2 formas de leer esta pregunta, y las respuestas existentes cubren ambas interpretaciones: CUALQUIERA: (a) preservar los archivos con los nombres especificados ubicados directamente en el directorio de destino y, como rm -rimplica, eliminar todo lo demás, incluidos los subdirectorios , incluso si contienen archivos con los nombres especificados; O: (b) recorra todo el subárbol del directorio de destino y, en cada directorio, elimine todos los archivos excepto aquellos con los nombres listados.
mklement0
Respuestas:
219
find [path]-type f -not -name 'textfile.txt'-not -name 'backup.tar.gz'-delete
Si no especifica -type fbuscar, también se enumerarán los directorios, que quizás no desee.
O una solución más general usando la combinación muy útil find | xargs:
Recibo un "error de sintaxis cerca del token inesperado` ('"cuando lo hago shopt -s extglob; rm -rf !(README|LICENSE). ¿Alguna idea de por qué?
Dennis
@nic No lo recuerdo, lo siento. Probablemente terminé usando findla -deleteopción.
Dennis
Esta es la mejor solución para mí y funciona de manera predeterminada en mi Ubuntu 12.04.4 LTS sin necesidad de comprar
xtian
3
@nic, @Dennis: el error de sintaxis sugiere que bashse usó algo que no sea , por ejemplo dash, donde extglobno se admite. Sin embargo, en un shell interactivobash , el comando TAMBIÉN no funcionará como se indica, aunque por diferentes razones. En resumen: ejecutar shopt -s extglobPOR SÍ MISMO; UNA VEZ CON ÉXITO HABILITADO (verificar con shopt extglob), ejecutar rm -rf !(README|LICENSE). (Si bien extglobaún no está activada, !(...)se evalúa por la expansión de historia antes de ejecutar los comandos, ya que esto probablemente no, NI se ejecuta el comando, y extglob. No está activada)
mklement0
2
@nic, @Dennis, @ mklement0: Tuve el mismo problema con "error de sintaxis cerca de token inesperado (" al ejecutar el comando dentro de un archivo .sh (#! / bin / bash) pero no cuando lo estaba ejecutando en un comando interfaz de línea. Resultó que además de la shopt -s extglobejecución en la interfaz de línea de comando, tuve que volver a ejecutarlo dentro de mi archivo de script. Esto resolvió el problema para mí.
Esto enumerará todos los archivos en el directorio actual, luego enumerará todos aquellos que no coincidan con sus criterios (tenga cuidado con los nombres de directorio coincidentes) y luego elimínelos.
Actualización : en función de su edición, si realmente desea eliminar todo del directorio actual, excepto los archivos que enumeró, se puede usar:
Creará un directorio de respaldo /tmp_backup(tiene privilegios de root, ¿verdad?), Moverá los archivos que enumeró a ese directorio, eliminará recursivamente todo en el directorio actual (sabe que está en el directorio correcto, ¿verdad?), Muévase volver al directorio actual de todo /tmp_backupy finalmente, eliminar /tmp_backup.
Elijo el directorio de respaldo para que esté en la raíz, porque si está tratando de eliminar todo de forma recursiva de la raíz, su sistema tendrá grandes problemas.
Seguramente hay formas más elegantes de hacer esto, pero esta es bastante sencilla.
También funciona muy bien con egrep, por ejemplo, para limpiar archivos intermedios de látex:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz
comando increíble! para eliminar directorios simplemente cambie a rm -r
Aris
1
Si desea simplemente eliminar todo en el directorio actual que no sea el criterio excluido: find . -maxdepth 1 | grep -v "exclude these" | xargs rm -rfunciona mucho más rápido ya que no necesita profundizar en directorios innecesariamente.
billynoah
Re findpipeline: dejando a un lado los problemas de eficiencia (se usan 3 comandos para lo que findpodría hacer solo), esto no funcionará como se espera con los nombres de archivo con espacios incrustados y potencialmente eliminará los archivos incorrectos.
mklement0
Un comando que almacena archivos "para ser guardados" en otra ubicación ( /tmp_backup) no termina bien si se interrumpe: desde la perspectiva del usuario, todos los archivos han desaparecido, a menos que sepan dónde buscarlos para recuperarlos. . Por eso no estoy a favor de este tipo de estrategia.
Craig McQueen
20
Suponiendo que los archivos con esos nombres existen en varios lugares en el árbol de directorios y desea conservarlos todos:
find .-type f !-regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)"-delete
Establecer GLOBIGNORE de esta manera ignora php y sql de los comodines utilizados como "ls *" o "rm *". Entonces, el uso de "rm *" después de configurar la variable eliminará solo el archivo txt y tar.gz.
Es más complicado porque tienes que ocuparte de los permisos después de copiarlos.
Romulus
2
@RemusAvram Puede usar los interruptores apropiados con cpo rsyncpara preservar los permisos. De todos modos, este es solo un método alternativo (dado como una sugerencia) que tiene su lugar aquí, como respuesta al OP.
gniourf_gniourf
Esto puede no ser apropiado en muchas situaciones en las que los archivos a retener están siendo utilizados activamente por otros procesos. También es engorroso que los archivos que se van a eliminar son solo un pequeño subconjunto y hay una gran cantidad de archivos involucrados.
codeforester
@codeforester: claro. Pero hay situaciones en las que es apropiado, sin embargo ... de hecho, realmente no veo el punto de tu comentario :).
gniourf_gniourf
6
Puede escribir un bucle for para esto ...%)
for x in*doif["$x"!="exclude_criteria"]then
rm -f $x;fidone;
Un poco tarde para el OP, pero espero que sea útil para cualquiera que llegue mucho más tarde por Google ...
Encontré la respuesta de @awi y el comentario sobre -delete de @Jamie Bullock realmente útil. Una utilidad simple para que pueda hacer esto en diferentes directorios ignorando diferentes nombres / tipos de archivos cada vez con un mínimo de escritura:
pero los nombres con espacios son (como siempre) difíciles. Intenté también con Virtualbox\ VMslas comillas. Elimina siempre ese directorio ( Virtualbox VMs).
NO funciona para archivos. rm !(myfile.txt)elimina todo incluidomyfile.txt
khaverim
debería ejecutarse shopt -s extglobprimero como señaló @ pl1nk
zhuguowei
Sí, es muy importante activar el globbing extendido ( extglob ) en bash, lo hago a diario, en algunos Macs en los laboratorios: shopt -s extgloby luego cd /Users/alumno/y finalmente rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) Lea sobre globbing extendido aquí
juanfal
4
Sólo:
rm $(ls -I "*.txt")#Deletes file type except *.txt
Después de eso, recorra todos los archivos en el directorio que desea excluir, verificando si el nombre del archivo está en la matriz que no desea excluir; si no es así, elimine el archivo.
for file in*;doif[[!" ${files[@]} "~="$file"]];then
rm "$file"fidone
La comparación de expresiones regulares es incorrecta: conservará cualquier archivo cuyo nombre sea una subcadena de uno de los archivos protegidos (aunque los espacios circundantes mitigan algo; pero los nombres de archivo pueden contener espacios). Debe recopilar una matriz de todos los archivos, luego restar los archivos que desea excluir de esa matriz y luego eliminar los archivos restantes.
tripleee
-1
Como nadie ha mencionado esto aún, en un caso particular:
OLD_FILES=`echo *`... create new files ...
rm -r $OLD_FILES
(o solo rm $OLD_FILES)
o
OLD_FILES=`ls *`... create new files ...
rm -r $OLD_FILES
Es posible que necesite usar shopt -s nullglobsi algunos archivos pueden estar allí o no:
La respuesta existente de Leonardo Hermoso hace esto con menos errores. Esto fallará para los nombres de archivo con espacios; El uso de una matriz resuelve elegantemente ese problema en particular (y también evita de manera menos crucial el uso de mayúsculas para sus variables privadas, que generalmente se debe evitar).
tripleee
-3
En lugar de buscar un comando directo, mueva los archivos necesarios al directorio temporal fuera del directorio actual. Luego, elimine todos los archivos con rm *o rm -r *.
Luego mueva los archivos requeridos al directorio actual.
Esto puede no ser apropiado en muchas situaciones en las que los archivos a retener están siendo utilizados activamente por otros procesos. También es engorroso que los archivos que se van a eliminar son solo un pequeño subconjunto y hay una gran cantidad de archivos involucrados.
codeforester
-3
Eliminar todo, excluir file.name:
ls -d /path/to/your/files/*|grep -v file.name|xargs rm -rf
Esto fallará horriblemente y podría causar la pérdida de datos si su directorio / archivos tienen espacios o caracteres inusuales. Nunca deberías analizar ls. mywiki.wooledge.org/ParsingLs
rm -r
implica, eliminar todo lo demás, incluidos los subdirectorios , incluso si contienen archivos con los nombres especificados; O: (b) recorra todo el subárbol del directorio de destino y, en cada directorio, elimine todos los archivos excepto aquellos con los nombres listados.Respuestas:
Si no especifica
-type f
buscar, también se enumerarán los directorios, que quizás no desee.O una solución más general usando la combinación muy útil
find | xargs
:por ejemplo, elimine todos los archivos que no sean txt en el directorio actual:
La combinación
print0
y-0
es necesaria si hay espacios en alguno de los nombres de archivo que deben eliminarse.fuente
find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
-print0 | xargs -0 rm --
usted puede simplemente-delete
Extglob (Extended Pattern Matching) debe habilitarse en BASH (si no está habilitado):
fuente
shopt -s extglob; rm -rf !(README|LICENSE)
. ¿Alguna idea de por qué?find
la-delete
opción.bash
se usó algo que no sea , por ejemplodash
, dondeextglob
no se admite. Sin embargo, en un shell interactivobash
, el comando TAMBIÉN no funcionará como se indica, aunque por diferentes razones. En resumen: ejecutarshopt -s extglob
POR SÍ MISMO; UNA VEZ CON ÉXITO HABILITADO (verificar conshopt extglob
), ejecutarrm -rf !(README|LICENSE)
. (Si bienextglob
aún no está activada,!(...)
se evalúa por la expansión de historia antes de ejecutar los comandos, ya que esto probablemente no, NI se ejecuta el comando, yextglob
. No está activada)shopt -s extglob
ejecución en la interfaz de línea de comando, tuve que volver a ejecutarlo dentro de mi archivo de script. Esto resolvió el problema para mí.find . | grep -v "excluded files criteria" | xargs rm
Esto enumerará todos los archivos en el directorio actual, luego enumerará todos aquellos que no coincidan con sus criterios (tenga cuidado con los nombres de directorio coincidentes) y luego elimínelos.
Actualización : en función de su edición, si realmente desea eliminar todo del directorio actual, excepto los archivos que enumeró, se puede usar:
Creará un directorio de respaldo
/tmp_backup
(tiene privilegios de root, ¿verdad?), Moverá los archivos que enumeró a ese directorio, eliminará recursivamente todo en el directorio actual (sabe que está en el directorio correcto, ¿verdad?), Muévase volver al directorio actual de todo/tmp_backup
y finalmente, eliminar/tmp_backup
.Elijo el directorio de respaldo para que esté en la raíz, porque si está tratando de eliminar todo de forma recursiva de la raíz, su sistema tendrá grandes problemas.
Seguramente hay formas más elegantes de hacer esto, pero esta es bastante sencilla.
fuente
find . | egrep -v "\.tex|\.bib" | xargs rm
find . -maxdepth 1 | grep -v "exclude these" | xargs rm -r
funciona mucho más rápido ya que no necesita profundizar en directorios innecesariamente.find
pipeline: dejando a un lado los problemas de eficiencia (se usan 3 comandos para lo quefind
podría hacer solo), esto no funcionará como se espera con los nombres de archivo con espacios incrustados y potencialmente eliminará los archivos incorrectos./tmp_backup
) no termina bien si se interrumpe: desde la perspectiva del usuario, todos los archivos han desaparecido, a menos que sepan dónde buscarlos para recuperarlos. . Por eso no estoy a favor de este tipo de estrategia.Suponiendo que los archivos con esos nombres existen en varios lugares en el árbol de directorios y desea conservarlos todos:
fuente
Puede usar la variable de entorno GLOBIGNORE en Bash.
Supongamos que desea eliminar todos los archivos excepto php y sql, luego puede hacer lo siguiente:
Establecer GLOBIGNORE de esta manera ignora php y sql de los comodines utilizados como "ls *" o "rm *". Entonces, el uso de "rm *" después de configurar la variable eliminará solo el archivo txt y tar.gz.
fuente
GLOBIGNORE
variable es usar una subshell:(GLOBIGNORE='*.php:*.sql'; rm *)
Prefiero usar la lista de subconsultas:
fuente
Como nadie lo mencionó:
fuente
cp
orsync
para preservar los permisos. De todos modos, este es solo un método alternativo (dado como una sugerencia) que tiene su lugar aquí, como respuesta al OP.:)
.Puede escribir un bucle for para esto ...%)
fuente
Un poco tarde para el OP, pero espero que sea útil para cualquiera que llegue mucho más tarde por Google ...
Encontré la respuesta de @awi y el comentario sobre -delete de @Jamie Bullock realmente útil. Una utilidad simple para que pueda hacer esto en diferentes directorios ignorando diferentes nombres / tipos de archivos cada vez con un mínimo de escritura:
rm_except (o como quieras nombrarlo)
Por ejemplo, para eliminar todo excepto los archivos de texto y foo.bar:
Similar a @mishunika, pero sin la cláusula if.
fuente
Si está utilizando
zsh
lo que recomiendo encarecidamente.Con
extended_glob
fuente
Probarlo funcionó con:
pero los nombres con espacios son (como siempre) difíciles. Intenté también con
Virtualbox\ VMs
las comillas. Elimina siempre ese directorio (Virtualbox VMs
).fuente
rm !(myfile.txt)
elimina todo incluidomyfile.txt
shopt -s extglob
primero como señaló @ pl1nkshopt -s extglob
y luegocd /Users/alumno/
y finalmenterm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library)
Lea sobre globbing extendido aquíSólo:
O:
fuente
ls
salida puede convertirse en un problema es. Consulte aquí para obtener información detallada.Haz los archivos inmutables. Ni siquiera root podrá eliminarlos.
Todos los demás archivos han sido eliminados.
Finalmente, puede restablecerlos mutable.
fuente
Esto es similar al comentario de @ siwei-shen pero necesita la
-o
bandera para hacer múltiples patrones. La-o
bandera significa 'o'find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm
fuente
Puede hacer esto con dos secuencias de comandos. Primero defina una matriz con el nombre de los archivos que no desea excluir:
Después de eso, recorra todos los archivos en el directorio que desea excluir, verificando si el nombre del archivo está en la matriz que no desea excluir; si no es así, elimine el archivo.
fuente
Como nadie ha mencionado esto aún, en un caso particular:
(o solo
rm $OLD_FILES
)o
Es posible que necesite usar
shopt -s nullglob
si algunos archivos pueden estar allí o no:sin nullglob,
echo *.sh *.bash
puede darle "a.sh b.sh * .bash".(Habiendo dicho todo eso, prefiero esta respuesta , aunque no funciona en OSX)
fuente
En lugar de buscar un comando directo, mueva los archivos necesarios al directorio temporal fuera del directorio actual. Luego, elimine todos los archivos con
rm *
orm -r *
.Luego mueva los archivos requeridos al directorio actual.
fuente
Eliminar todo, excluir file.name:
fuente