Почему моя команда `find` выдаёт мне ошибки, связанные с игнорируемыми каталогами? - PullRequest
0 голосов
/ 08 мая 2018

У меня есть команда поиска:

find . -type f  -not -path '**/.git/**' -not -path '**/node_modules/**'  | xargs sed -i '' s/typescript-library-skeleton/xxx/g;

почему-то выдает мне следующие предупреждения / ошибки:

find: ./.git/objects/3c: No such file or directory
find: ./.git/objects/3f: No such file or directory
find: ./.git/objects/41: No such file or directory

Я даже пытался использовать:

-not -path '**/.git/objects/**'

и получил то же самое. Кто-нибудь знает, почему поиск ищет в каталоге .git? Кажется странным.

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

почему поиск находит в каталоге .git?

GNU find является умным и поддерживает несколько оптимизаций по сравнению с наивной реализацией:

  • Он может перевернуть порядок -size +512b -name '*.txt' и сначала проверить имя, потому что для запроса размера потребуется второй системный вызов.
  • Он может сосчитать жесткие ссылки каталога, чтобы определить количество подкаталогов, и когда он все видит, ему больше не нужно проверять их на -type d или на повторяемость.
  • Он может даже переписать (-B -or -C) -and -A, так что, если проверки одинаково дороги и не имеют побочных эффектов, сначала будет оцениваться -A, в надежде отклонить файл после 1 теста вместо 2.

Однако , это еще не достаточно умно, чтобы понять, что -not -path '*/.git/*' означает, что если вы найдете каталог .git, вам даже не нужно возвращаться в него, потому что все файлы внутри потерпят неудачу чтобы соответствовать.

Вместо этого он покорно повторяет, находит каждый файл и сопоставляет его с шаблоном, как если бы это был черный ящик.

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

0 голосов
/ 08 мая 2018

И более эффективным, и более правильным было бы избежать действия по умолчанию -print, изменить -not -path ... на -prune и убедиться, что xargs используется только с вводом, разделенным NUL:

find . -name .git -prune -o \
       -name node_modules -prune -o \
       -type f -print0 | xargs -0 sed -i '' s/typescript-library-skeleton/xxx/g '{}' +

Обратите внимание на следующие моменты:

  • Мы используем -prune, чтобы сказать find, чтобы он даже не рекурсировал нежелательные каталоги, вместо -not -path ..., чтобы сказать ему отбрасывать имена в этих каталогах после того, как они были найдены .
  • Мы ставим -prune s перед на -type f, чтобы мы могли сопоставлять каталоги для сокращения.
  • У нас есть явное действие , не зависящее от значения по умолчанию -print. Это важно, потому что по умолчанию -print фактически имеет набор скобок: find ... ведет себя как find '(' ... ')' -print, а не как find ... -print, нет, если задано явное действие.
  • Мы используем xargs только с аргументом -0, разрешающим ввод с разделением NUL, и действием -print0 на стороне find для создания списка имен с разделением NUL. NUL - это единственный символ, который не может присутствовать в произвольном пути к файлу (да, могут присутствовать символы новой строки) - и, таким образом, символ only , который безопасно использовать для разделения путей. (Если расширение -0 до xargs и расширение -print0 до find не гарантируется, используйте вместо этого -exec sed -i '' ... {} +).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...