Встроенная история, кажется, отключена в сценарии оболочки. Посмотрите здесь: http://www.tldp.org/LDP/abs/html/histcommands.html
Я не нашел официальной документации об этом.
(Ваш вопрос не ясен: если каталог содержит some.foo
и some.bar
, это должно быть удалено? Я интерпретировал его как требование, чтобы такой каталог был сохранен.)
Следующий сценарий должен работать, при условии, что никакое имя файла не содержит новую строку и никакие соответствия каталога *.foo
. Принцип должен пересечь каталог от листов (-depth
), и как *.foo
с файлами встречаются, содержание каталога и всех родителей отмечено как protected
. Любой достигнутый файл, который не является *.foo
и не защищенный каталог, который будет удален. Из-за -depth
пересекающийся порядок, каталог всегда достигается после *.foo
файлы, которые могли бы защитить его. Предупреждение: минимально протестированный, удалите echo
на Ваш собственный риск.
find . -depth -name '*.foo' -o -type d | awk '{
if ($0 ~ /\.foo$/) {
while (sub("/+[^/]+$", "")) {protect[$0]=1;}
} else {
if (!protect[$0]) {
gsub("[\\\001-/]", "\\\\&"); # protect file names for xargs
print;
}
}
}' | xargs echo rm -rf
На этот раз я не предлагаю zsh решения.
Я не совсем уверен, что это может быть сделано с помощью только find
, но я думаю, что мы можем сделать это с помощью только bash
и find
.
tree_contains_foo_files()
{
# return true (0) as soon as we find a "*.foo" file
find "$1" -type f -name "*.foo" -print0 |
read -r -d $'\0' file && return 0
return 1
}
find . -depth -type d -print0 |
while read -r -d $'\0' dir; do
if ! tree_contains_foo_files "$dir"; then
rm -rf "$dir"
fi
done
Учитывая это тестовое дерево:
.
./dir1
./dir1/dir1.1
./dir1/dir1.1/dir1.1.1
./dir1/dir1.1/dir1.1.1/file.foo
./dir1/dir1.1/file.bar
./dir2
./dir2/dir2.1
./dir2/file.bar
./dir3
Я получаю этот результат:
rm -rf ./dir2/dir2.1
rm -rf ./dir2
rm -rf ./dir3
то, которое я думаю, - то, что Вы хотите, т.е. не удаляете dir1
, потому что dir1/dir1.1/dir1.1.1
содержит file.foo
.
Но обратите внимание, что это делает рабочие каталоги многократно, таким образом, это могло бы быть медленно для больших деревьев. Если бы эффективность важна, я использовал бы более мощный язык программирования.
tree_contains_foo_files
, такой как [ -n "$(find … | head -c 1)" ]
, или (быстрее, но требует, GNU находит), [ -n "$(find … -printf a -quit)" ]
.
– Gilles 'SO- stop being evil'
02.03.2011, 01:34
read
уже, как насчет find ... | read file && return 0
. Я думаю, что это очень немного быстрее снова.
– Mikel
02.03.2011, 03:21
IIUYC, можно просто сначала удалить все нежелательное использование файлов
find . ! -type f -name '*.foo' -delete
который может освободить некоторые каталоги. Затем можно удалить пустые каталоги (и каталоги, содержащие только пустые каталоги, и т.д.) как в моем вопросе
find . -depth -mindepth 1 -empty -type d -exec rmdir -p -- {} +
Если разрешено больше, чем просто find
, гораздо более простое решение:
find -type d -not -path . | while IFS='' read -r path; do [[ ! -e "$path/$notThisFile" ]] && echo "$path"; done
Замените -e
любым тестом, который вам нравится.
Это должно напечатать вам все подкаталоги, которые не содержат $ notThisFile
.
Подробный пример, где выделяются все нескрытые подкаталоги, содержащие файл:
find -type d -not -path . | while IFS='' read -r path; do
[[ ! -e "$path/$notThisFile" ]] && echo "$path"
done | sed -r 's~^([^.]*)/'"$notThisFile"'$~\033[1;37m\1\033[0m~''
File::Find
был бы правильный инструмент для этого задания. – Gilles 'SO- stop being evil' 02.03.2011, 01:27[\\\011-/]
кому:[\011-]
. – Mikel 02.03.2011, 03:28"[\001-]"
(Я принимаю\011
опечатка), соответствует только\001
и-
, который бесполезен, так как точка должна защитить\\'"
и пробел. – Gilles 'SO- stop being evil' 02.03.2011, 09:58\001
. – Mikel 02.03.2011, 10:53