Остановить рекурсию команды find, если совпадение найдено - PullRequest
0 голосов
/ 07 февраля 2019

Используя GNU findutils, мне нужно найти дерево каталогов для определенного файла.Если файл был найден для данной ветки, я хочу предотвратить повторный поиск find в ветке.Скажем, я хочу найти файл foo, и это мое дерево каталогов:

├── a
│   ├── a1
│   │   └── foo
│   └── foo
├── b
└── c
    └── foo

Учитывая, что я ищу дерево выше, я хочу найти / foo и c / foo.Однако я не хочу находить / a1 / foo, так как я уже нашел foo в родительском каталоге для a1.Кажется, я должен использовать флаг -prune для команды find, и я нашел эту ссылку, например, https://unix.stackexchange.com/questions/24557/how-do-i-stop-a-find-from-descending-into-found-directories,, но я не могу заставить ее работать.Мои попытки включают в себя:

$ find -name foo -type f -prune
./a/a1/foo <- Unwanted hit
./a/foo
./c/foo

и

$ find -name foo -type f -prune -exec find ../foo -type f {} \;
find: paths must precede expression: ./a/a1/foo
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
find: paths must precede expression: ./a/foo
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
find: paths must precede expression: ./c/foo
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

это не может быть легко сделано с помощью find -prune, потому что он работает с каталогами, а базовые условия поиска - над текущим файлом.

альтернативой может быть программное использование bash с использованием рекурсивной функции,в основном

rec_run() {
    local file
    for file in "${1:-.}"/*; do
        # to filter 'file=*' when no match is found
        if [[ ! -e $file ]]; then
            continue
        fi

        # do something with file
        echo "$file"

        # to filter known hard links
        if [[ $file = */. ]] || [[ $file = */.. ]]; then
            continue
        fi

        # if is a directory recursive call
        if [[ -d $file ]]; then
            rec_run "$file";
        fi
    done
}

и изменение детали # do something с помощью

    if [[ -f $file/foo ]]; then
        echo "$file/foo"
        continue
    fi

здесь foo жестко закодировано, но может быть передано как второй аргумент функции

Примечание ${1:-.} должен принимать первый аргумент в качестве корневого каталога или ., если не передан

0 голосов
/ 07 февраля 2019

При этом будут напечатаны каталоги, содержащие foo, и они не будут повторяться в своих подкаталогах:

find -type d -exec test -f {}/foo \; -print -prune

Поведение для {}/foo явно не определено POSIX :

Если строка служебного_имя или аргумента содержит два символа "{}", а не только два символа "{}", определяется реализацией, заменяет ли find эти два символа или использует строкубез изменений.

, но работает с GNU find как и ожидалось (и вы пометили вопрос с помощью ).Как справедливо показывает Камил Цук в комментариях, если вы используете не-GNU find или хотите более портативное решение, используйте:

find -type d -exec sh -c 'test -f "$1"/foo' -- {} \; -print -prune
...