Почему порядок -prune и -path изменяет вывод команды find?

Вопрос или проблема

На этот вопрос дан ответ на другом stackexchange (stackoverflow), но я не смог его найти, потому что искал ответ здесь. Я публикую свой вопрос здесь, чтобы следующий человек мог легче найти ответ. Я отмечу это как дубликат.

ИЗМЕНЕНИЕ: Видимо, вы не можете использовать ссылку на другой stackexchange, чтобы закрыть вопрос как дубликат, поэтому я ответил на свой собственный вопрос ниже.


Я заметил эти несколько похожие вопросы, но я не понимаю, как эти ответы применимы к моему конкретному случаю. Вот две команды, которые я запускаю:

#1
find . -path '*/node_modules/*' -prune -o -name '*js' -print # выводит файлы
#2
find . -prune -path '*/node_modules/*' -o -name '*js' -print # не выводит файлы

Согласно этому ответу, я думал, что это сокращенная форма для:

#1
find . '('                                               \
           '(' -path '*/node_modules/*' -a -prune ')' -o \
           '(' -name '*js' ')'                           \
       ')' -a -print
#2
find . '('                                               \
           '(' -prune -a -path '*/node_modules/*' ')' -o \
           '(' -name '*js' ')'                           \
       ')' -a -print

Я прочитал страницу man для -prune, и она кажется простой. Почему я получаю результаты только тогда, когда ставлю -path перед -prune?

Источник: https://stackoverflow.com/questions/1489277/how-to-use-prune-option-of-find-in-sh

То, что мне показалось запутанным в -prune, это то, что это действие
(как -print), а не тест (как -name). Оно изменяет “список дел”,
но всегда возвращает true.

Общий шаблон для использования -prune выглядит так:

find [путь] [условия для отсечения] -prune -o \
            [ваши обычные условия] [действия для выполнения]

Вы, в общем, всегда хотите, чтобы -o (логическое ИЛИ) находился сразу после
-prune, потому что первая часть теста (включая
-prune) вернет false для вещей, которые вам на самом деле нужны (т.е. вещей, которые вы не хотите отсекать).

Вот пример:

find . -name .snapshot -prune -o -name '*.foo' -print

Это найдет файлы “*.foo”, которые не находятся в директориях “.snapshot”.
В этом примере -name .snapshot образует
[условия для отсечения], а -name '*.foo' -print — это [ваши обычные условия] и [действия для выполнения].

Важно отметить:

  1. Если все, что вы хотите сделать, это вывести результаты, вы можете быть привычны не указывать действие -print. Вы, как правило, не хотите этого
    при использовании -prune.

    Поведение по умолчанию для find — это “и” всей выражения с действием -print, если в конце нет других действий, кроме -prune
    (иронично). Это означает, что написание этого:

     find . -name .snapshot -prune -o -name '*.foo'              # НЕ ДЕЛАЙТЕ ЭТО
    

    равноценно написанию этого:

     find . \( -name .snapshot -prune -o -name '*.foo' \) -print # НЕ ДЕЛАЙТЕ ЭТО
    

    что означает, что оно также выведет имя директории, которую вы отсечете, что обычно не то, что вы хотите. Вместо этого лучше
    явно указать действие -print, если это то, что вы хотите:

     find . -name .snapshot -prune -o -name '*.foo' -print       # ДЕЛАЙТЕ ЭТО
    
  2. Если ваше “обычное условие” соответствует файлам, которые также соответствуют вашему условию отсечения, эти файлы не будут включены в
    вывод. Исправить это можно, добавив предикат -type d к вашему
    условию отсечения.

    Например, предположим, что мы хотим отсечь любую директорию, которая начинается с .git (это, признаться, несколько вычурно — обычно
    вам нужно просто удалить элемент с именем ровно .git), но кроме этого хотим видеть все файлы, включая файлы вроде .gitignore.
    Вы могли бы попробовать это:

    find . -name '.git*' -prune -o -type f -print               # НЕ ДЕЛАЙТЕ ЭТО
    

    Это не включит .gitignore в вывод. Вот исправленная версия:

    find . -name '.git*' -type d -prune -o -type f -print       # ДЕЛАЙТЕ ЭТО
    

Дополнительный совет: если вы используете версию find от GNU, страница texinfo
для find
содержит более подробное объяснение, чем его man-страница
(как это верно для большинства утилит GNU).

Ответ или решение

Почему порядок -prune и -path изменяет результаты команды find

Команда find — это мощный инструмент для поиска файлов и каталогов в Unix-подобных системах. Однако порядок, в котором вы используете параметры -prune и -path, может существенно повлиять на результаты поиска. Давайте детально разберем, как это работает.

Определение ключевых параметров

  1. -prune: Этот параметр является действием, который указывает find игнорировать (пропустить) указанные каталоги, но он всегда возвращает истину (true). Это означает, что указанные каталоги и их содержимое не будут обработаны или исследованы дальше.

  2. -path: Этот параметр служит для указания путей, которые вы хотите найти. Он является условием (тестом), и если условие выполнено, то процесс поиска будет продолжен.

Примеры команд

Рассмотрим два примера, которые были приведены в вашем вопросе:

# Пример 1
find . -path '*/node_modules/*' -prune -o -name '*js' -print  # выводит файлы

# Пример 2
find . -prune -path '*/node_modules/*' -o -name '*js' -print  # не выводит ничего

Как это работает

  1. Пример 1:

    В этом примере -path идет перед -prune. Оператор -prune используется для того, чтобы игнорировать каталоги, которые соответствуют шаблону */node_modules/*. Однако поскольку -path идет первым, поиск сначала проверяет, соответствует ли текущий файл шаблону. Если это так, find применяет -prune, что прекращает дальнейшую обработку подкаталогов. Поскольку в конце используется -o, find продолжает искать файлы с расширением .js и выводит их.

  2. Пример 2:

    В данном случае порядок параметров изменен. -prune теперь идет перед -path. Это означает, что первая проверка будет выполнять действие -prune, и find будет игнорировать все файлы и каталоги, которые соответствуют шаблону. Поскольку после этого не остается файлов для дальнейшей проверки, другие условия, такие как -name '*js', не будут оценены. Это приводит к отсутствию результатов.

Почему это важно?

Порядок применения -prune и -path критически важен для достижения правильного поведения команды find. Очевидно, что -prune по своей природе "прерывает" процесс поиска каталогов, и если он расположен в начале, вы можете полностью пропустить файлы, соответствующие другим условиям.

Подведение итогов

Чтобы получить ожидаемые результаты при использовании команды find, помните о следующем:

  • Порядок имеет значение: Убедитесь, что -prune следует за условиями, которые вы хотите применить.
  • Структура условий: Помните, что действие -prune изменяет логику поиска и может полностью заблокировать результаты, если используется неуместно.
  • Тестирование: Не стесняйтесь тестировать различные комбинации и порядок параметров для достижения оптимальных результатов.

Соблюдение этих принципов позволит вам эффективно использовать команду find в ваших задачах по поиску файлов и каталогов.

Оцените материал
Добавить комментарий

Капча загружается...