6

Почему в Linux (Debian 8)

touch 1.cpp 1.h
find . -name "*.cpp" -o -name "*.h" -exec echo {} \;

выводит только 1.h пока

find . -name "*.cpp" -o -name "*.h"

выводит оба? Это ошибка или особенность?

4 ответа4

1

Я думаю, что как только вы использовали оператор -or , вы должны поддерживать его согласованность, чтобы избежать неоднозначного порядка логических операций, когда у вас есть несколько условий, связанных с использованием логического ИЛИ.

Кажется, часть -exec сгруппирована вместе со вторым -name "*.h" .

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

find . '(' -name '*.cpp' -o -name '*.h' ')' -exec echo {} ';'

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

Также можно объединить несколько расширений в одно с помощью -regex:

find . ! -regex ".*\.\(cpp\|h\)" -exec echo {} \;
1

Попробуйте заключить критерии поиска в такие скобки:

find . \( -name "*.cpp" -o -name "*.h" \) -exec echo {} \;
1

Ни. Это синтаксис опций, который "неверен". 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 {} \;
0

Именно так 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 {} \;)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .