Почему в Linux (Debian 8)
touch 1.cpp 1.h
find . -name "*.cpp" -o -name "*.h" -exec echo {} \;
выводит только 1.h
пока
find . -name "*.cpp" -o -name "*.h"
выводит оба? Это ошибка или особенность?
Я думаю, что как только вы использовали оператор -or
, вы должны поддерживать его согласованность, чтобы избежать неоднозначного порядка логических операций, когда у вас есть несколько условий, связанных с использованием логического ИЛИ.
Кажется, часть -exec
сгруппирована вместе со вторым -name "*.h"
.
Поэтому, чтобы заставить его работать правильно, вы должны добавить скобки, как показано ниже:
find . '(' -name '*.cpp' -o -name '*.h' ')' -exec echo {} ';'
Помните: круглые скобки должны быть заключены в кавычки или экранированы обратной косой чертой, чтобы их нельзя было интерпретировать как специальные символы оболочки.
Также можно объединить несколько расширений в одно с помощью -regex
:
find . ! -regex ".*\.\(cpp\|h\)" -exec echo {} \;
Попробуйте заключить критерии поиска в такие скобки:
find . \( -name "*.cpp" -o -name "*.h" \) -exec echo {} \;
Ни. Это синтаксис опций, который "неверен". find
оценивает последовательно. Следовательно, он оценивает первое выражение (-name "*.cpp"
), а затем встречает флаг -o
. Если первое выражение истинно, find
не будет продолжать вычислять второе (-name "*.h" -exec echo {} \;
), вместо этого ничего не делает. Видите ли, вся часть после -o
- это одно выражение. Следовательно, это выполняется только для файлов, которые соответствуют второму выражению. Поэтому вы видите только файл 1.h
, который передает только второе выражение. Смотрите страницу поиска:
expr1 -o expr2
Or; expr2 is not evaluated if expr1 is true.
Почему это полезно? Учтите следующее:
find /path -exec test_file_for_something {} -print \; -o -name "xyz" -exec ls -l {} \;
В этом операторе поиска файл передается test_file_for_something
в качестве параметра. Теперь, в зависимости от того, что команды возвращают код, первое выражение имеет значение true (затем выполняется -print
и заканчивается там) или false (затем выполняется второе выражение после флага -o
). И если это правда (имя xyz
), то выполняется -exec
.
Для вашей проблемы вы можете использовать это, чтобы сгруппировать элементы вместе в одно выражение:
find . \( -name "*.cpp" -o -name "*.h" \) -exec echo {} \;
Именно так find работает с его операторами.
Смотрите http://linux.die.net/man/1/find раздел ОПЕРАТОРЫ
ОПЕРАТОРЫ
Перечислено в порядке убывания приоритета: (expr) Форсировать приоритет. Так как круглые скобки являются специальными для оболочки, вам обычно нужно их заключать в кавычки. Во многих примерах на этой странице руководства для этой цели используется обратная косая черта: '(...)' вместо '(...)». ! expr Истинно, если expr ложно. Этот персонаж также обычно нуждается в защите от интерпретации оболочкой.
-не expr То же, что и! expr, но не POSIX-совместимый. expr1 expr2 Два выражения в строке берутся с подразумеваемыми "и"; expr2 не оценивается, если expr1 имеет значение false. expr1 -a expr2 То же, что expr1 expr2. expr1 -and expr2 То же, что expr1 expr2, но не POSIX-совместимый. expr1 -o expr2 или; expr2 не оценивается, если expr1 имеет значение true. expr1 -или expr2 То же, что expr1 -o expr2, но не POSIX-совместимый. список expr1, expr2; оба expr1 и expr2 всегда оцениваются. Значение expr1 отбрасывается; значение списка - это значение expr2. Оператор запятой может быть полезен для поиска нескольких различных типов вещей, но обход иерархии файловой системы только один раз. Действие -fprintf можно использовать для перечисления различных совпадающих элементов в несколько разных выходных файлов.
Это должно дать вам результат, который вы хотите:
находить . \(-name '* .cpp' -o -name '* .h' \) -exec echo {} \;
Ваша команда делает это (команда не будет работать, просто чтобы показать вам логику):
находить . -name '* .cpp' (-o -name '* .h' -exec echo {} \;)