it-swarm.com.de

So durchlaufen Sie ein Verzeichnis rekursiv, um Dateien mit bestimmten Erweiterungen zu löschen

Ich muss ein Verzeichnis rekursiv durchlaufen und alle Dateien mit den Endungen .pdf und.doc entfernen. Ich kann ein Verzeichnis rekursiv durchlaufen, aber nicht die Dateien mit den oben genannten Dateierweiterungen filtern.

Mein Code bisher

#/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

Ich brauche Hilfe, um den Code zu vervollständigen, da ich nicht weiterkomme.

138
Roland

find ist nur dafür gemacht.

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

Als Folge der Antwort von mouviciel können Sie dies auch als for-Schleife ausführen, anstatt xargs zu verwenden. Ich finde xargs oft umständlich, besonders wenn ich in jeder Iteration etwas Komplizierteres machen muss.

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

Wie einige kommentiert haben, schlägt dies fehl, wenn die Dateinamen Leerzeichen enthalten. Sie können dies umgehen, indem Sie das IFS (Internal Field Seperator) vorübergehend auf das Newline-Zeichen setzen. Dies schlägt auch fehl, wenn die Dateinamen Platzhalterzeichen \[?* Enthalten. Sie können das umgehen, indem Sie die Platzhaltererweiterung (Globbing) vorübergehend deaktivieren.

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

Wenn Ihre Dateinamen Zeilenumbrüche enthalten, funktioniert das auch nicht. Mit einer auf xargs basierenden Lösung sind Sie besser dran:

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

(Die geschützten Klammern müssen hier angegeben werden, damit -print0 Auf beide or -Klauseln angewendet wird.)

GNU und * BSD find haben auch eine -delete - Aktion, die so aussehen würde:

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

Ohne find:

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

/tmp/* sind Dateien in dir und /tmp/**/* sind Dateien in Unterordnern. Möglicherweise müssen Sie die Globstar-Option (shopt -s globstar). Für die Frage sollte der Code also so aussehen:

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

Beachten Sie, dass hierfür bash ≥4.0 erforderlich ist (oder zsh ohne shopt -s globstar oder ksh mit set -o globstar anstatt shopt -s globstar). Darüber hinaus werden in bash <4.3 sowohl symbolische Links zu Verzeichnissen als auch zu Verzeichnissen durchlaufen, was normalerweise nicht wünschenswert ist.

54
Tomek

Wenn Sie etwas rekursiv machen wollen, schlage ich vor, dass Sie die Rekursion verwenden (ja, Sie können es mit Stacks und so weiter machen, aber hey).

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

(cd /tmp; recursiverm)

Das heißt, find ist wahrscheinlich eine bessere Wahl, wie bereits vorgeschlagen wurde.

25
falstro

Hier ist ein Beispiel mit 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
14
Eric Wang

Dies beantwortet Ihre Frage nicht direkt, aber Sie können Ihr Problem mit einem Einzeiler lösen:

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

Einige Versionen von find (GNU, BSD) haben ein -delete Aktion, die Sie verwenden können, anstatt rm aufzurufen:

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

Diese Methode behandelt Leerzeichen gut.

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

Bearbeiten, Korrekturen nacheinander

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
}
7
TJR

Für Bash (seit Version 4.0):

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

Das ist alles.
Die nachfolgende Erweiterung ".ext", um Dateien (oder Verzeichnisse) mit dieser Erweiterung auszuwählen.

Option globstar aktiviert die ** (Suche rekursiv).
Die Option nullglob entfernt ein *, wenn es mit keiner Datei/keinem Verzeichnis übereinstimmt.
Option dotglob enthält Dateien, die mit einem Punkt beginnen (versteckte Dateien).

Beachten Sie, dass vor der Bash 4.3, **/ durchläuft auch symbolische Links zu Verzeichnissen, was nicht erwünscht ist.

3
user2350426

Die folgende Funktion durchläuft rekursiv alle Verzeichnisse im Verzeichnis \home\ubuntu (Gesamte Verzeichnisstruktur unter Ubuntu) und wendet die erforderlichen Prüfungen im Block else an.

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
1
K_3

Es gibt keinen Grund, die Ausgabe von find an ein anderes Dienstprogramm weiterzuleiten. find hat ein -delete Fahne eingebaut.

find /tmp -name '*.pdf' -or -name '*.doc' -delete
0
Zak

Die angegebenen Antworten enthalten keine Dateien oder Verzeichnisse, die mit a beginnen. bei mir hat folgendes geklappt:

#/bin/sh
getAll()
{
  local fl1="$1"/*;
  local fl2="$1"/.[!.]*; 
  local fl3="$1"/..?*;
  for inpath in "$1"/* "$1"/.[!.]* "$1"/..?*; do
    if [ "$inpath" != "$fl1" -a "$inpath" != "$fl2" -a "$inpath" != "$fl3" ]; then 
      stat --printf="%F\0%n\0\n" -- "$inpath";
      if [ -d "$inpath" ]; then
        getAll "$inpath"
      #Elif [ -f $inpath ]; then
      fi;
    fi;
  done;
}
0
TrevTheDev