Как циклически перебирать каталог для удаления файлов с определенными расширениями

Мне нужно циклически перебирать каталог и удалять все файлы с расширением .pdf и .doc, мне удается рекурсивно перебирать каталог, но не удалять файлы для фильтрации с вышеупомянутыми расширениями файлов.

Мой код пока

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

Мне нужна помощь для завершения кода, так как я никуда не денусь.

Ответ 1

find только для этого.

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

Ответ 2

В качестве продолжения ответа mouviciel вы также можете сделать это как цикл for, вместо использования xargs. Я часто нахожу xargs громоздким, особенно если мне нужно сделать что-то более сложное на каждой итерации.

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

Как прокомментировал ряд людей, это не удастся, если в именах файлов есть пробелы. Вы можете обойти это, временно установив IFS (внутренний разделитель полей) на символ новой строки. Это также терпит неудачу, если в именах файлов есть подстановочные знаки \[?*. Вы можете обойти это, временно отключив расширение подстановки (globbing).

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

Если у вас есть новые строки в ваших именах файлов, это тоже не сработает. Вам лучше с решением на основе xargs:

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

(Спрятанные скобки требуются здесь для привязки -print0 к обоим предложениям or.)

GNU и * BSD find также имеют действие -delete, которое будет выглядеть так:

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

Ответ 3

Без find:

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

/tmp/* - файлы в каталоге, а /tmp/**/* - файлы в подпапках. Возможно, вам нужно включить опцию globstar (shopt -s globstar). Поэтому для вопроса код должен выглядеть следующим образом:

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

Обратите внимание, что для этого требуется bash ≥4.0 (или zsh без shopt -s globstar, или ksh с set -o globstar вместо shopt -s globstar). Кроме того, в bash < 4.3 это перемещает символические ссылки на каталоги, а также каталоги, которые обычно нежелательны.

Ответ 4

Если вы хотите что-то рекурсивно, я предлагаю вам использовать рекурсию (да, вы можете сделать это с помощью стеков и т.д., но эй).

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

(cd /tmp; recursiverm)

Тем не менее, find, вероятно, лучший выбор, как уже было предложено.

Ответ 5

Вот пример использования оболочки (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

Ответ 6

Это не отвечает на ваш вопрос напрямую, но вы можете решить свою проблему с помощью однострочного интерфейса:

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

В некоторых версиях find (GNU, BSD) есть действие -delete, которое вы можете использовать вместо вызова rm:

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

Ответ 7

Этот метод хорошо обрабатывает пробелы.

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

Изменить, исправлять "один за другим"

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
}

Ответ 8

Для bash (начиная с версии 4.0):

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

Что все. Завершающее расширение ".ext" позволяет выбирать файлы (или dirs) с этим расширением.

Опция globstar активирует ** (поиск рекурсивно).
Опция nullglob удаляет *, когда он не соответствует файлу/директории.
Опция dotglob включает файлы, начинающиеся с точки (скрытые файлы).

Остерегайтесь того, что перед bash 4.3, **/ также пересекает символические ссылки на каталоги, которые нежелательны.

Ответ 9

Следующая функция рекурсивно перебирает все каталоги в каталоге \home\ubuntu (целая структура каталогов в ubuntu) и применяет необходимые проверки в блоке 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

Ответ 10

Просто сделай

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

Ответ 11

Далее будет рекурсивно проходить через данный каталог и отобразить все содержимое:

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