bash - una - eliminar archivos por extension
Cómo recorrer un directorio recursivamente para eliminar archivos con ciertas extensiones (11)
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.
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
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
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
}
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
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
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
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.
Si quieres hacer algo de manera recursiva, te sugiero que utilices la recursión (sí, puedes hacerlo usando pilas 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.
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.
Solo haz
find . -name ''*.pdf''|xargs rm
find
está hecho para eso.
find /tmp -name ''*.pdf'' -or -name ''*.doc'' | xargs rm