используйте 'находят' для поиска каталогов! содержа определенное нечто типа файла

Встроенная история, кажется, отключена в сценарии оболочки. Посмотрите здесь: http://www.tldp.org/LDP/abs/html/histcommands.html

Я не нашел официальной документации об этом.

5
04.03.2011, 16:45
4 ответа

(Ваш вопрос не ясен: если каталог содержит 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 решения.

3
27.01.2020, 20:38
  • 1
    Возможно, File::Find был бы правильный инструмент для этого задания. –  Gilles 'SO- stop being evil' 02.03.2011, 01:27
  • 2
    я получаю ошибку на awk строке сценария 5 выполнений, что, но кажется OK, если я изменяюсь [\\\011-/] кому: [\011-]. –  Mikel 02.03.2011, 03:28
  • 3
    @Mikel: это странно, я не получаю ошибки при Простофиле, Mawk или исходном awk, и я не вижу то, что могло быть неправильным. Ваш regexp "[\001-]" (Я принимаю \011 опечатка), соответствует только \001 и -, который бесполезен, так как точка должна защитить \\'" и пробел. –  Gilles 'SO- stop being evil' 02.03.2011, 09:58
  • 4
    Да, извините, я имел в виду \001. –  Mikel 02.03.2011, 10:53

Я не совсем уверен, что это может быть сделано с помощью только 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.

Но обратите внимание, что это делает рабочие каталоги многократно, таким образом, это могло бы быть медленно для больших деревьев. Если бы эффективность важна, я использовал бы более мощный язык программирования.

2
27.01.2020, 20:38
  • 1
    Существуют более эффективные внедрения 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
  • 2
    Спасибо за предложение. Вы правы, что я должен закоротить, как только файл найден. Наблюдение, поскольку я использую read уже, как насчет find ... | read file && return 0. Я думаю, что это очень немного быстрее снова. –  Mikel 02.03.2011, 03:21
  • 3
    Или конечно find ... | read -n 1 .... –  Mikel 02.03.2011, 03:31

IIUYC, можно просто сначала удалить все нежелательное использование файлов

find . ! -type f -name '*.foo' -delete

который может освободить некоторые каталоги. Затем можно удалить пустые каталоги (и каталоги, содержащие только пустые каталоги, и т.д.) как в моем вопросе

find . -depth -mindepth 1 -empty -type d -exec rmdir -p -- {} +
1
27.01.2020, 20:38

Если разрешено больше, чем просто 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~''
1
27.01.2020, 20:38

Теги

Похожие вопросы