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


Мне нужно циклически перебирать каталог и удалять все файлы с расширением .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

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


112


источник


Ответы:


find просто сделано для этого.

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

109



В ответ на ответ мувициля вы также можете сделать это как цикл 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

161



Без 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 это пересекает символические ссылки на каталоги, а также каталоги, что обычно нежелательно.


47



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

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

(cd /tmp; recursiverm)

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


23



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

10



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

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



This method handles spaces well.

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

Edit, fixes off-by-one

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
}

6



The following function would recursively iterate through all the directories in the \home\ubuntu directory( whole directory structure under ubuntu ) and apply the necessary checks in else block.

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