Cómo recorrer un directorio recursivamente para eliminar archivos con ciertas extensiones

Necesito recorrer un directorio recursivamente y eliminar todos los archivos con extensión .pdf y.doc, estoy logrando recorrer un directorio recursivamente pero sin filtrar los archivos con las extensiones de archivo mencionadas anteriormente.

Mi código hasta el momento

#/bin/sh SEARCH_FOLDER="/tmp/*" for f in $SEARCH_FOLDER do if [ -d "$f" ] then for ff in $f/* do echo "Processing $ff" done else echo "Processing file $f" fi done 

Necesito ayuda para completar el código, ya que no estoy llegando a ningún lado.

find está hecho para eso.

 find /tmp -name '*.pdf' -or -name '*.doc' | xargs rm 

Como seguimiento de la respuesta de mouviciel, también puedes hacer esto como un bucle for, en lugar de usar xargs. A menudo me parece engorroso xargs, especialmente si necesito hacer algo más complicado en cada iteración.

 for f in $(find /tmp -name '*.pdf' -or -name '*.doc'); do rm $f; done 

Como varias personas han comentado, esto fallará si hay espacios en los nombres de archivo. Puede solucionar esto estableciendo temporalmente el IFS (separador de campo interno) en el carácter de nueva línea. Esto también falla si hay caracteres comodín \[?* En los nombres de archivo. Puede solucionarlo desactivando temporalmente la expansión de comodines (globbing).

 IFS=$'\n'; set -f for f in $(find /tmp -name '*.pdf' -or -name '*.doc'); do rm "$f"; done unset IFS; set +f 

Si tiene nuevas líneas en sus nombres de archivo, entonces eso tampoco funcionará. Está mejor con una solución basada en xargs:

 find /tmp \( -name '*.pdf' -or -name '*.doc' \) -print0 | xargs -0 rm 

(Aquí se requieren los corchetes escapados para que el -print0 aplique a ambas or cláusulas).

GNU y * BSD find también tienen una acción de -delete , que se vería así:

 find /tmp \( -name '*.pdf' -or -name '*.doc' \) -delete 

Sin find :

 for f in /tmp/* tmp/**/* ; do ... done; 

/tmp/* son archivos en dir y /tmp/**/* son archivos en subcarpetas. Es posible que deba habilitar la opción shopt -s globstar ( shopt -s globstar ). Entonces, para la pregunta, el código debería verse así:

 shopt -s globstar for f in /tmp/*.pdf /tmp/*.doc tmp/**/*.pdf tmp/**/*.doc ; do rm "$f" done 

Tenga en cuenta que esto requiere bash ≥4.0 (o zsh sin shopt -s globstar , o ksh con el set -o globstar lugar de shopt -s globstar ). Además, en bash <4.3, esto atraviesa enlaces simbólicos a directorios y directorios, lo que generalmente no es deseable.

Si quieres hacer algo de manera recursiva, te sugiero que utilices la recursión (sí, puedes hacerlo usando stacks y demás, pero bueno).

 recursiverm() { for d in *; do if [ -d "$d" ]; then (cd -- "$d" && recursiverm) fi rm -f *.pdf rm -f *.doc done } (cd /tmp; recursiverm) 

Dicho esto, find es probablemente una mejor opción, como ya se ha sugerido.

Aquí hay un ejemplo usando shell ( bash ):

 #!/bin/bash # loop & print a folder recusively, print_folder_recurse() { for i in "$1"/*;do if [ -d "$i" ];then echo "dir: $i" print_folder_recurse "$i" elif [ -f "$i" ]; then echo "file: $i" fi done } # try get path from param path="" if [ -d "$1" ]; then path=$1; else path="/tmp" fi echo "base path: $path" print_folder_recurse $path 

Esto no responde su pregunta directamente, pero puede resolver su problema con un solo trazo:

 find /tmp \( -name "*.pdf" -o -name "*.doc" \) -type f -exec rm {} + 

Algunas versiones de find (GNU, BSD) tienen una acción de -delete que puede usar en lugar de llamar a rm :

 find /tmp \( -name "*.pdf" -o -name "*.doc" \) -type f -delete 

Este método maneja bien los espacios.

 files="$(find -L "$dir" -type f)" echo "Count: $(echo -n "$files" | wc -l)" echo "$files" | while read file; do echo "$file" done 

Editar, arregla uno por uno

 function count() { files="$(find -L "$1" -type f)"; if [[ "$files" == "" ]]; then echo "No files"; return 0; fi file_count=$(echo "$files" | wc -l) echo "Count: $file_count" echo "$files" | while read file; do echo "$file" done } 

La siguiente función iteraría recursivamente a través de todos los directorios en el directorio \home\ubuntu (toda la estructura de directorios bajo ubuntu) y aplicaría las verificaciones necesarias en el bloque else .

 function check { for file in $1/* do if [ -d "$file" ] then check $file else ##check for the file if [ $(head -c 4 "$file") = "%PDF" ]; then rm -r $file fi fi done } domain=/home/ubuntu check $domain 

Para bash (desde la versión 4.0):

 shopt -s globstar nullglob dotglob echo **/*".ext" 

Eso es todo.
La extensión final “.ext” allí para seleccionar archivos (o directorios) con esa extensión.

La opción globstar activa ** (buscar recursivamente).
La opción nullglob elimina un * cuando no coincide con ningún archivo / directorio.
La opción dotglob incluye archivos que comienzan con un punto (archivos ocultos).

Tenga en cuenta que antes de bash 4.3, **/ también atraviesa enlaces simbólicos a directorios que no es deseable.

Solo haz

 find . -name '*.pdf'|xargs rm 

Lo siguiente recorrerá el directorio dado recursivamente y listará todos los contenidos:

for d in /home/ubuntu/*; do echo "listing contents of dir: $d"; ls -l $d/; done