Bash extglob с проигнорированным шаблоном

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

Предположим, у меня есть эти файлы:

foo/bar/baz/test.js
foo/bar/baz/test.min.js

Если я выполню:

shopt -s globstar
shopt -s extglob
echo foo/bar/**/*!(.min).js

…это все равно будет соответствовать файлу test.min.js.

Как мне его игнорировать?

В extglob, !(.min) может соответствовать всему, кроме .min (и всего, что содержит /); это включает пустую строку!

Когда вы проверяете foo/bar/baz/test.min.js с помощью глоба foo/bar/**/*!(.min).js, вы получаете совпадение, потому что:

  • foo/bar/ соответствует foo/bar/
  • **/ соответствует bar/
  • * соответствует test.min
  • !(.min) соответствует пустой строке
  • .js соответствует .js

То значение, которое вы хотите получить от !(.min), – это на самом деле “все, что не заканчивается на .min“, что является отрицанием *.min, поэтому используйте !(*.min), чтобы исправить проблему:

foo/bar/**/!(*.min).js

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

Использование Bash extglob с игнорированием паттернов: Подробное руководство

При работе с Bash и его механизмами сопоставления шаблонов, такими как globbing и extglob, возникают ситуации, когда необходимо исключить определённые файлы из результатов поиска. Один из наиболее распространённых случаев — это игнорирование файлов с определёнными расширениями, как в примере с файлами JavaScript в директории. Давайте подробно рассмотрим, как это сделать, и исправить потенциальные ошибки в шаблонах.

Проблема

У вас есть два файла:

  • foo/bar/baz/test.js
  • foo/bar/baz/test.min.js

При исполнении следующей команды вы ожидаете вывести только файл test.js:

shopt -s globstar
shopt -s extglob
echo foo/bar/**/*!(.min).js

Однако результатом будет:

foo/bar/baz/test.js
foo/bar/baz/test.min.js

Это происходит потому, что шаблон !(.min) не работает так, как ожидается. Давайте разберемся почему.

Причины проблемы

При использовании шаблона !(.min), Bash рассматривает это как "всё, что не является .min", и к тому же принимает во внимание пустую строку. Таким образом, шаблон будет соответствовать как test.js, так и test.min.js, поскольку !(.min) может совпасть с пустым значением.

Разбор сопоставления

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

  1. foo/bar/ соответствует foo/bar/.
  2. **/ соответствует bar/.
  3. * соответствует test.min.
  4. !(.min) соответствует пустой строке.
  5. .js соответствует .js.

Таким образом, test.min.js также подходит под данный шаблон.

Решение

Чтобы корректно игнорировать файлы с .min, нужно использовать другой подход. Вместо !(.min) используется !(*.min), что интерпретируется как "всё, что не заканчивается на .min". Это позволяет исключить все соответствующие файлы.

Используйте следующий шаблон в вашей команде:

echo foo/bar/**/!(*.min).js

Итоги

Теперь, когда вы выполнили обновлённый шаблон, вы получите правильный результат, исключающий файлы с .min:

foo/bar/baz/test.js

Рекомендации

  • Всегда проверяйте, как ваши шаблоны взаимодействуют с пустыми строками и другими символами.
  • Изучайте различные способы использования extglob, чтобы избегать распространённых ошибок в простых сценариях работы с файлами.
  • Используйте встроенные возможности Bash, такие как shopt, для оптимизации вашего рабочего процесса.

Знание таких нюансов значительно улучшит вашу продуктивность как специалиста в IT и позволит эффективно управлять файлами в системах на основе Unix.

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

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