Comment faire une boucle dans un répertoire de façon récursive pour supprimer des fichiers avec certaines extensions
je dois boucler un répertoire récursivement et supprimer tous les fichiers avec extension .pdf et.doc, j'arrive à boucler un répertoire récursivement mais pas à filtrer les fichiers avec les extensions de fichiers mentionnées ci-dessus.
Mon code jusqu'à présent
#/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
j'ai besoin d'aide pour compléter le code, puisque je ne vais nulle part.
11 réponses
find
est juste fait pour ça.
find /tmp -name '*.pdf' -or -name '*.doc' | xargs rm
pour faire suite à la réponse de mouviel, vous pouvez également le faire en boucle, au lieu d'utiliser xargs. Je trouve souvent xargs encombrant, surtout si j'ai besoin de faire quelque chose de plus compliqué à chaque itération.
for f in $(find /tmp -name '*.pdf' -or -name '*.doc'); do rm $f; done
comme un certain nombre de personnes ont commenté, cela échouera s'il y a des espaces dans les noms de fichiers. Vous pouvez contourner cela en réglant Temporairement L'IFS (internal field seperator) sur le caractère newline. Cela échoue aussi s'il y a un joker caractères \[?*
dans les noms de fichier. Vous pouvez contourner cela en désactivant temporairement l'extension de Joker (globbing).
IFS=$'\n'; set -f
for f in $(find /tmp -name '*.pdf' -or -name '*.doc'); do rm "$f"; done
unset IFS; set +f
si vous avez newlines dans vos noms de fichiers, alors cela ne fonctionnera pas non plus. Vous êtes mieux avec une solution basée sur xargs:
find /tmp \( -name '*.pdf' -or -name '*.doc' \) -print0 | xargs -0 rm
(les crochets évités sont nécessaires ici pour que le -print0
s'applique aux deux clauses or
.)
GNU et * BSD find a aussi un -delete
action, qui ressemblerait à ceci:
find /tmp \( -name '*.pdf' -or -name '*.doc' \) -delete
sans find
:
for f in /tmp/* tmp/**/* ; do
...
done;
/tmp/*
sont des fichiers dans dir et /tmp/**/*
sont des fichiers dans des sous-dossiers. Il est possible que vous deviez activer l'option globstar ( shopt -s globstar
).
Donc pour la question le code devrait ressembler à ceci:
shopt -s globstar
for f in /tmp/*.pdf /tmp/*.doc tmp/**/*.pdf tmp/**/*.doc ; do
rm "$f"
done
noter que cela nécessite bash ≥4,0 (ou zsh sans shopt -s globstar
, ou ksh avec set -o globstar
au lieu de shopt -s globstar
). De plus, à bash < 4.3, ceci traverse des liens symboliques aux annuaires aussi bien qu'aux annuaires, ce qui n'est généralement pas souhaitable.
si vous voulez faire quelque chose de façon récursive, je vous suggère d'utiliser la récursion (oui, vous pouvez le faire en utilisant des piles et ainsi de suite, mais hé).
recursiverm() {
for d in *; do
if [ -d "$d" ]; then
(cd -- "$d" && recursiverm)
fi
rm -f *.pdf
rm -f *.doc
done
}
(cd /tmp; recursiverm)
cela dit, find
est probablement un meilleur choix comme cela a déjà été suggéré.
voici un exemple d'utilisation de shell ( bash
):
#!/bin/bash
# loop & print a folder recusively,
print_folder_recurse() {
for i in ""/*;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 "" ]; then
path=;
else
path="/tmp"
fi
echo "base path: $path"
print_folder_recurse $path
cela ne répond pas directement à votre question, mais vous pouvez résoudre votre problème avec une doublure unique:
find /tmp \( -name "*.pdf" -o -name "*.doc" \) -type f -exec rm {} +
certaines versions de find (GNU, BSD) ont une action -delete
que vous pouvez utiliser au lieu d'appeler rm
:
find /tmp \( -name "*.pdf" -o -name "*.doc" \) -type f -delete
cette méthode gère bien les espaces.
files="$(find -L "$dir" -type f)"
echo "Count: $(echo -n "$files" | wc -l)"
echo "$files" | while read file; do
echo "$file"
done
d'Éditer, de correctifs hors-en-un
function count() {
files="$(find -L "" -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
}
pour bash (depuis la version 4.0):
shopt -s globstar nullglob dotglob
echo **/*".ext"
C'est tout.
La fuite d'extension ".ext" là pour sélectionner des fichiers (ou des Drs) avec cette extension.
L'Option globstar active le * * (recherche récurrente).
L'Option nullglob supprime un * lorsqu'il ne correspond à aucun fichier/dir.
L'Option dotglob inclut les fichiers qui commencent par un point (fichiers cachés).
Attention, avant bash 4.3, **/
traverse aussi des liens symboliques vers des répertoires qui ne sont pas souhaitables.
la fonction suivante itérerait récursivement à travers tous les répertoires du répertoire \home\ubuntu
(structure de répertoire entière sous ubuntu ) et appliquerait les vérifications nécessaires dans le bloc else
.
function check {
for file in /*
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
ce qui suit fera une boucle récursive dans le répertoire donné et énumérera tous les contenus:
for d in /home/ubuntu/*;
do
echo "listing contents of dir: $d";
ls -l $d/;
done