Eliminar todos los archivos excepto los archivos con la extensión pdf en un directorio

50

Tengo un directorio que contiene lo siguiente:

x.pdf
y.zip
z.mp3
a.pdf

Quiero eliminar todos los archivos aparte de x.pdfy a.pdf. ¿Cómo hago esto desde la terminal? No hay subdirectorios, por lo que no es necesario recurrir.

Starkers
fuente

Respuestas:

63
cd <the directory you want>
find . -type f ! -iname "*.pdf" -delete
  • El primer comando lo llevará al directorio en el que desea eliminar sus archivos.
  • El segundo comando eliminará todos los archivos excepto aquellos que terminen .pdfen nombre de archivo

Por ejemplo, si hay un directorio llamado tempen su carpeta de inicio:

cd ~/temp

luego borre los archivos:

find . -type f ! -iname "*.pdf" -delete

Esto eliminará todos los archivos excepto xyz.pdf.

Puede combinar estos dos comandos para:

find ~/temp -type f ! -iname "*.pdf" -delete

.es el directorio actual !significa tomar todos los archivos excepto los que están .pdfal final. -type fselecciona solo archivos, no directorios. -deletesignifica eliminarlo.

NOTA: este comando eliminará todos los archivos (excepto los archivos pdf pero incluidos los archivos ocultos) en el directorio actual, así como en todos los subdirectorios. !debe venir antes -name. simplemente -nameincluirá solo .pdf, mientras -inameque incluirá ambos .pdfy.PDF

Para eliminar solo en el directorio actual y no en los subdirectorios, agregue -maxdepth 1:

find . -maxdepth 1 -type f ! -iname "*.pdf" -delete
Edward Torvalds
fuente
Gracias por la respuesta. ¿Me pueden ayudar a entender un poco la sintaxis? .significa "y"? !significa "excepto" -namesignifica que desea excluir mediante un parámetro de nombre y, ¿cuál -deletees la acción que debe tomar al encontrarlo? Entonces, ¿busca todo excepto "* .pdf" y los elimina? ¿O he entendido mal?
jessenorton
.significa directorio actual. !significa tomar todos los archivos excepto el que está .pdfal final. -deletesignifica eliminarlo. ¿Estoy claro ahora?
Edward Torvalds
@terdon Starkers dijo que no hay subdirectorios.Espero editar mi respuesta para que sea más amplia
Edward Torvalds
+1 Deberías haber incluido el -maxdepth 1parámetro para empezar. Luego sugiera eliminar el parámetro en caso de que se quiera eliminar de forma recursiva.
Tulains Córdova
3
Esto me llamó la atención que deberíamos usar en -inamelugar de -name, o los archivos con .PDFuna extensión se deslizarán.
muru
43

Con bashel globing de shell extendido, puede eliminar cualquier archivo con extensiones que no sean .pdfusar

rm -- *.!(pdf)

Como señaló @pts, los --caracteres indican el final de cualquier opción de comando, haga que el comando sea seguro en el raro caso de archivos cuyos nombres comiencen con un -carácter.

Si desea eliminar archivos sin ninguna extensión, así como aquellos con extensiones que no sean .pdf, entonces, como lo señaló @DennisWilliamson, podría usar

rm -- !(*.pdf)

El globbing extendido debe estar habilitado de forma predeterminada, pero si no, puede hacerlo utilizando

shopt -s extglob

Especialmente si tiene la intención de usar esto dentro de un script, es importante tener en cuenta que si la expresión no coincide con nada (es decir, si no hay archivos que no sean pdf en el directorio), de forma predeterminada, el globo se pasará sin expandir al rmcomando, lo que resulta en un error como

rm: cannot remove `*.!(pdf)': No such file or directory

Puede modificar este comportamiento predeterminado utilizando la nullglobopción de shell, sin embargo, eso tiene su propio problema. Para una discusión más completa ver NullGlob - Greg's Wiki

conductor de acero
fuente
Mejor acercamiento a la OMI.
Takkat
¿Qué pasa con los archivos sin extensión? FWIW, en zsh esrm *~*.pdf
Emil Jeřábek 01 de
1
Pondría el punto dentro de los paréntesis.
Dennis Williamson
44
Ah, el asterisco también debe ir dentro: !(*.py). Además, presumiblemente, si el OP solo quiere archivos ".pdf" restantes, entonces los archivos sin extensiones también deberían eliminarse y no ignorarse.
Dennis Williamson
1
Este enfoque es más simple y ordenado que la respuesta aceptada.
Peter
18

Eliminar a la papelera :

$ cd <the directory you want>
$ gvfs-trash !(*.pdf)

O a través de un mvcomando (pero de esta manera no puede restaurarlo desde la Papelera ya que no registra información .trashinfo, por lo que esto significa que movió sus archivos a un destino donde está de la siguiente manera).

mv !(*.pdf) ~/.local/share/Trash/files
αғsнιη
fuente
66
Este enfoque es mucho más seguro que usarlo directamente rm.
Seth
14

El enfoque más fácil: cree otro directorio en algún lugar (si solo está eliminando en un directorio, no de forma recursiva, incluso puede ser un subdirectorio); mueve todos los archivos .pdf allí; eliminar todo lo demás; mueve el pdf hacia atrás; Eliminar el directorio intermedio.

Rápido, fácil, puedes ver exactamente lo que estás haciendo. ¡Solo asegúrese de que el directorio intermedio esté en el mismo dispositivo que el directorio que está limpiando para que los movimientos sean renombrados, no copias!

alemán
fuente
44
+1 De nuevo para un comentario que tenga sentido para el usuario novato, que seguramente no dará como resultado la eliminación involuntaria de archivos.
trognanders
4

Utilice el GLOBIGNORE de bash:

GLOBIGNORE=x.pdf:a.pdf
rm *
unset GLOBIGNORE

De la página de manual de bash:

GLOBIGNORE:

            Una lista de patrones separados por dos puntos que definen el conjunto
            de nombres de archivo a ignorar por la expansión de nombre de ruta.

Una prueba rápida:

mkdir /tmp/foooooo
cd /tmp/foooooo
touch x.pdf y.zip z.mp3 a.pdf
GLOBIGNORE=x.pdf:a.pdf
ls -1 *

Salida:

y.zip
z.mp3
Ciro
fuente
3

Tenga cuidado y componga: use xargs

Aquí hay un enfoque que me gusta, porque me permite ser muy cuidadoso: componga una forma de mostrar solo los archivos que quiero eliminar y luego envíelos a rmusar xargs. Por ejemplo:

  • ls me muestra todo
  • ls | grep pdfme muestra los archivos que quiero conservar. Hmm
  • ls | grep -v pdfmuestra lo contrario: todo excepto lo que quiero conservar. En otras palabras, muestra la lista de cosas que quiero eliminar. Puedo confirmar esto antes de hacer algo peligroso.
  • ls | grep -v pdf | xargs rmenvía exactamente esa lista rmpara su eliminación

Como dije, me gusta principalmente por la seguridad que proporciona: no es accidental rm *para mí. Otras dos ventajas:

  • Es composable; puede usar lso findpara obtener la lista inicial, como prefiera. Puede usar cualquier otra cosa que desee en el proceso de reducir esa lista: otra grep, alguna awko lo que sea. Si necesita eliminar solo archivos cuyos nombres contienen un color, puede crearlo de la misma manera.
  • Puede usar cada herramienta para su propósito principal. Prefiero usar findpara buscar y rmeliminar, en lugar de tener que recordar que findacepta una -deletebandera. Y si hace esto, nuevamente, puede componer soluciones alternativas; tal vez en lugar de rm, podría crear un trashcomando que mueva el archivo a la papelera (permitiendo "eliminar") y canalizarlo a ese en lugar de rm. No necesita tener findsoporte para esa opción, solo tiene que canalizarla.

Actualizar

Vea los comentarios de @pabouk para ver cómo modificar esto para manejar algunos casos extremos, como saltos de línea en nombres de archivos, nombres de archivos como my_pdfs.zip, etc.

Nathan Long
fuente
44
Noté tres problemas aquí: a) Excluirá cualquier archivo que contenga pdfcualquier parte de su nombre. --- b) Eliminará los archivos PDF si alguna de las letras del sufijo es mayúscula. --- c) No es una buena idea utilizar la salida de ls. No funcionará con nombres de archivo que contengan nuevas líneas. Algunas implementaciones de lsreemplazar caracteres especiales, por ejemplo, tab ?. --- Es mejor uso: find -maxdepth 1 -print0. (no tan corto como ls:) ----- Para resolver a) yb) use grep -vi '\.pdf$'--- solución completa (pero solo GNU):find -maxdepth 1 -print0 | grep -viz '\.pdf$' | xargs -0 rm
pabouk
1
Entiendo que se refería a la solución como un proceso "interactivo" con múltiples iteraciones manuales, pero las comprobaciones difícilmente serán utilizables para largas listas de archivos y los problemas mencionados anteriormente podrían traer errores fáciles de ignorar.
pabouk
1
@pabouk buenos puntos; El mundo real siempre complica las cosas, y sus correcciones son útiles. :) Pero sigo pensando que este enfoque general es el mejor. Si hay demasiados archivos para confirmar visualmente todo, | head -20al menos puede ver si se ve más o menos correcto, mientras que si simplemente rm my_patternno tiene la oportunidad de detectar un gran error.
Nathan Long
1
Puede hacer que find le muestre los archivos antes de eliminarlos también, omita el -delete y simplemente use find . -type f ! -name "*.pdf"para imprimir en la consola, o canalizar a menos o un archivo. [y luego canalice a xargs a rm si lo desea, como los comentarios de pabouk (con el -print0 | ... -0 para nombres de archivo extraños)]
Xen2050
3

Por lo general, resuelvo estos problemas con el intérprete interactivo de Python:

mic@mic ~ $ python
>>> import os
>>> for f in os.listdir('.'):
...   if not f.endswith('.pdf'):
...     os.remove(f)

Puede ser más largo que una línea con findo xargs, pero es extremadamente resistente y sé exactamente lo que hace, sin tener que investigarlo primero.

ratones
fuente
Para aquellos que se ponen cada vez más nerviosos con cada línea adicional, podríamos convertirlo en uno:for item in [f for f in os.listdir('.') if not f.endswith('.pdf')]: os.remove(item)
Jacob Vlijm
python -c "import os; for f in os.listdir('.'): if not f.endswith('.pdf'): os.remove(f)"
mic_e
[os.remove(f) for f in os.listdir('.') if not f.endswith('.pdf')]
mic_e
¡bonito! el segundo me da un error de sintaxis, no veo por qué.
Jacob Vlijm
extraño; funciona con python 3.4 y python 2.7 en mi sistema.
mic_e
2

La mejor respuesta (en comparación con mi respuesta anterior) a esta pregunta será utilizando el poderoso filecomando.

$ file -i abc.pdf
abc: application/pdf; charset=binary

ahora tu problema:

cd <the directory you want to search in>
for var in ./*
do
if file -i "$var" | grep -q 'application/pdf\;'
then
echo "$var"
fi
done

el trabajo de forcomando es dar los archivos en el directorio actual en forma de variable $var. if-thenEl comando genera los nombres de los archivos pdf tomando el estado de salida 0del file -i "$var" | grep -q 'application/pdf\;'comando from , dará el estado de salida de 0solo si encuentra archivos pdf.

Edward Torvalds
fuente
1
rm $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')

¡Advertencia! Mejor inténtalo primero

ls -l $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')
Martín-Blas Pérez Pinilla
fuente
2
Ugh, esto es defectuoso de muchas maneras: smallo.ruhr.de/award.html#ls , smallo.ruhr.de/award.html#grep , e ignora totalmente los nombres de archivos con espacios en blanco o caracteres especiales.
David Foerster
1
Realmente deberías usar -icon greppara la combinación de mayúsculas y minúsculas
muru
1
rm -i -- !(*@(a|x).pdf)

Leer como, eliminar todos los archivos que no son a.pdfo x.pdf.

Esto funciona mediante la utilización de globos 2 extendidos, el exterior !()para negar el pegote contenida que a su vez requiere que el pegote debe coincidir con uno o más de ao xpatrones antes del .pdfsufijo. Ver glob # extglob .

$ ls -a
.dotfile1 .dotfile2 a.pdf x.pdf y.zip z.mp3

$ echo -- !(a.pdf)
-- x.pdf y.zip z.mp3

$ echo -- !(x.pdf)
-- a.pdf y.zip z.mp3

$ echo -- !(a.pdf|x.pdf)
-- y.zip z.mp3

$ echo -- !(@(a|x).pdf)   # NOTE.that this matches the .dotfiles* as well
-- . .. .dotfile1 .dotfile2 y.zip z.mp3

$ echo -- !(*@(a|x).pdf)  # but this doesn't
-- y.zip z.mp3

$ echo rm -i -- !(*@(a|x).pdf)
rm -i -- y.zip z.mp3
shalomb
fuente
1

forma de concha portátil

$ ksh -c 'for i in ./*; do case $i in *.pdf)continue;; *)rm "$i";; esac;done'

Más o menos POSIX y compatible con cualquier cáscara de estilo Bourne ( ksh, bash, dash). Muy adecuado para scripts portátiles y cuando no se puede utilizar bashel globing de shell extendido.

perl:

$ perl -le 'opendir(my $d,"."); foreach my $f (grep(-f && !/.pdf/ , readdir($d))){unlink $f};closedir $d'                                                             

O un poco más limpio:

$ perl -le 'opendir(my $d,"."); map{ unlink $_ } grep(-f "./$_" && !/.pdf/ , readdir($d));closedir $d'

pitón alternativa

python -c 'import os;map(lambda x: os.remove(x), filter(lambda x: not x.endswith(".pdf"),os.listdir(".")))'
Sergiy Kolodyazhnyy
fuente
0

¡Ten cuidado con lo que estás borrando!

Una forma segura de probarlo antes de intentar eliminar es probar primero ls, ya que algunos comportamientos no detectados podrían eliminar archivos no deseados. Y puede hacerlo directamente fuera del directorio. lses similar a rm, entonces:

ls sub/path/to/files/!(*.pdf)

Esto listará

y.zip
z.mp3

Y ahora puede ver lo que está eliminando y puede eliminarlos de forma segura:

rm sub/path/to/files/!(*.pdf)

Y eso es. Puede usar comodines *para ser más selectivo, como conservar solo los documentos del curso de programación:

rm sub/path/to/files/!(*programming*)
KeitelDOG
fuente