Вопрос или проблема
На этот вопрос дан ответ на другом 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
, это то, что это действие
(как-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
— это[ваши обычные условия]
и[действия для выполнения]
.Важно отметить:
Если все, что вы хотите сделать, это вывести результаты, вы можете быть привычны не указывать действие
при использовании-prune
.Поведение по умолчанию для find — это “и” всей выражения с действием
-prune
(иронично). Это означает, что написание этого:find . -name .snapshot -prune -o -name '*.foo' # НЕ ДЕЛАЙТЕ ЭТО
равноценно написанию этого:
find . \( -name .snapshot -prune -o -name '*.foo' \) -print # НЕ ДЕЛАЙТЕ ЭТО
что означает, что оно также выведет имя директории, которую вы отсечете, что обычно не то, что вы хотите. Вместо этого лучше
явно указать действиеfind . -name .snapshot -prune -o -name '*.foo' -print # ДЕЛАЙТЕ ЭТО
Если ваше “обычное условие” соответствует файлам, которые также соответствуют вашему условию отсечения, эти файлы не будут включены в
вывод. Исправить это можно, добавив предикат-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
, может существенно повлиять на результаты поиска. Давайте детально разберем, как это работает.
Определение ключевых параметров
-
-prune: Этот параметр является действием, который указывает
find
игнорировать (пропустить) указанные каталоги, но он всегда возвращает истину (true). Это означает, что указанные каталоги и их содержимое не будут обработаны или исследованы дальше. -
-path: Этот параметр служит для указания путей, которые вы хотите найти. Он является условием (тестом), и если условие выполнено, то процесс поиска будет продолжен.
Примеры команд
Рассмотрим два примера, которые были приведены в вашем вопросе:
# Пример 1
find . -path '*/node_modules/*' -prune -o -name '*js' -print # выводит файлы
# Пример 2
find . -prune -path '*/node_modules/*' -o -name '*js' -print # не выводит ничего
Как это работает
-
Пример 1:
В этом примере
-path
идет перед-prune
. Оператор-prune
используется для того, чтобы игнорировать каталоги, которые соответствуют шаблону*/node_modules/*
. Однако поскольку-path
идет первым, поиск сначала проверяет, соответствует ли текущий файл шаблону. Если это так,find
применяет-prune
, что прекращает дальнейшую обработку подкаталогов. Поскольку в конце используется-o
,find
продолжает искать файлы с расширением.js
и выводит их. -
Пример 2:
В данном случае порядок параметров изменен.
-prune
теперь идет перед-path
. Это означает, что первая проверка будет выполнять действие-prune
, иfind
будет игнорировать все файлы и каталоги, которые соответствуют шаблону. Поскольку после этого не остается файлов для дальнейшей проверки, другие условия, такие как-name '*js'
, не будут оценены. Это приводит к отсутствию результатов.
Почему это важно?
Порядок применения -prune
и -path
критически важен для достижения правильного поведения команды find
. Очевидно, что -prune
по своей природе "прерывает" процесс поиска каталогов, и если он расположен в начале, вы можете полностью пропустить файлы, соответствующие другим условиям.
Подведение итогов
Чтобы получить ожидаемые результаты при использовании команды find
, помните о следующем:
- Порядок имеет значение: Убедитесь, что
-prune
следует за условиями, которые вы хотите применить. - Структура условий: Помните, что действие
-prune
изменяет логику поиска и может полностью заблокировать результаты, если используется неуместно. - Тестирование: Не стесняйтесь тестировать различные комбинации и порядок параметров для достижения оптимальных результатов.
Соблюдение этих принципов позволит вам эффективно использовать команду find
в ваших задачах по поиску файлов и каталогов.