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.

118
demandé sur user463035818 2011-01-09 14:23:58

11 réponses

find est juste fait pour ça.

find /tmp -name '*.pdf' -or -name '*.doc' | xargs rm
113
répondu mouviciel 2011-01-09 11:33:21

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
167
répondu James Scriven 2017-07-13 15:49:31

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.

48
répondu Tomek 2017-07-13 15:51:49

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é.

25
répondu falstro 2015-11-13 14:59:26

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
10
répondu Eric Wang 2015-12-06 03:52:07

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
8
répondu Oliver Charlesworth 2017-07-13 15:57:53

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
}
6
répondu TJR 2017-06-13 20:39:51

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.

2
répondu Gilles 2017-07-13 15:54:54

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
1
répondu K_3 2016-10-08 18:09:03

Just do

find . -name '*.pdf'|xargs rm
-1
répondu Navi 2013-02-20 09:45:10

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

-1
répondu S.K. Venkat 2014-10-07 12:03:22