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