Как циклически перебирать каталог для удаления файлов с определенными расширениями
Мне нужно циклически перебирать каталог и удалять все файлы с расширением .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
Мне нужна помощь для завершения кода, так как я никуда не денусь.
- -bash: ./my_script: / bin / bash ^ M: плохой интерпретатор: нет такого файла или каталога
- Проверка успеха команды в команде bash `if `
- Bash: вывести вывод команды в фоновом режиме
- Расширение Тильды в кавычках
- Сохранение текущего каталога в историю bash
- Получение ошибки «двусмысленного перенаправления»
- Как предотвратить появление команд в истории bash?
- скрипт bash для проверки запущенного процесса
- Как сохранить строки в строке в Bash?
- Использование: - (двоеточие в столбце) в bash
- Параллелизировать скрипт Bash с максимальным количеством процессов
- извлекать данные из файла журнала в указанный промежуток времени
- Как перечислять переменные, объявленные в скрипте в bash?
find
просто сделан для этого.
find /tmp -name '*.pdf' -or -name '*.doc' | xargs rm
В ответ на ответ мувициля вы также можете сделать это как цикл 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
скобки необходимы здесь для -print0
к обоим or
предложениям.)
GNU и * BSD find также имеют действие -delete
, которое будет выглядеть так:
find /tmp \( -name '*.pdf' -or -name '*.doc' \) -delete
Без find
:
for f in /tmp/* tmp/**/* ; do ... done;
/tmp/*
– файлы в каталоге dir и /tmp/**/*
– файлы в подпапках. Возможно, вам нужно включить опцию shopt -s 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 это пересекает символические ссылки на каталоги, а также каталоги, что обычно нежелательно.
Если вы хотите сделать что-то рекурсивно, я предлагаю вам использовать рекурсию (да, вы можете сделать это с помощью стеков и т. Д., Но эй).
recursiverm() { for d in *; do if [ -d "$d" ]; then (cd -- "$d" && recursiverm) fi rm -f *.pdf rm -f *.doc done } (cd /tmp; recursiverm)
Тем не менее, find
, вероятно, лучший выбор, как уже было предложено.
Вот пример использования 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
Это не отвечает на ваш вопрос напрямую, но вы можете решить свою проблему с помощью однострочного интерфейса:
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
Этот метод хорошо обрабатывает пространства.
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 }
Следующая функция рекурсивно перебирает все каталоги в каталоге \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
Для bash (начиная с версии 4.0):
shopt -s globstar nullglob dotglob echo **/*".ext"
Это все.
Конечное расширение «.ext» позволяет выбирать файлы (или dirs) с этим расширением.
Опция globstar активирует ** (поиск повторяется).
Параметр nullglob удаляет *, когда он не соответствует файлу / директории.
Опция dotglob включает файлы, начинающиеся с точки (скрытые файлы).
Помните, что до bash 4.3, **/
также пересекает символические ссылки на каталоги, которые нежелательны.
Просто делать
find . -name '*.pdf'|xargs rm
Далее будет рекурсивно проходить через данный каталог и отобразить все содержимое:
for d in /home/ubuntu/*; do echo "listing contents of dir: $d"; ls -l $d/; done