grep псевдоним для безопасного игнорирования нескольких каталогов

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

Ежедневное использование:

grep -rIn pattern directory

Есть некоторые файлы, которые я хочу исключить, они находятся в директориях с таким путем в какой-то момент: app/lib/bower/lodash, app/lib/bower/paho-mqtt-js, app/lib/bower/socket-io-client.

Идеальное решение — обнаружить app/lib/bower/ в пути, но это сложно. Возможно ли это?

Я придумал:

alias grep='grep --exclude-dir={lodash,paho-mqtt-js,socket-io-client}'

Достаточно хорошо (хотя требует поддержки, когда добавляются новые элементы). Как хотя бы добавить короткое предупреждение в stderr, если директория исключена grep?

Я бы использовал find:

mygrep() (
  pattern=$1; shift
  find "$@" -type d -path '*/app/lib/bower' -exec sh -c '
    printf >&2 "Warning: ignoring \"%s\" directory\n" "$@"
    ' sh {} + -prune -o -type f -exec grep -IHne "$pattern" {} +
)

(-I и -H являются расширениями GNU).

Используйте как:

mygrep pattern dir1 dir2

(убедитесь, что dir1 и dir2 не выглядят как предикаты find).

Удалите -exec sh...+, если вас не волнуют эти предупреждения.

Плохая идея использовать grep в качестве имени алиаса, если вы так радикально меняете его поведение.

Если вам нужно передать параметры в grep, вы можете использовать переменную GREP_OPTIONS, например:

GREP_OPTIONS=-i mygrep foo dir

Но обратите внимание, что поддержка этой опции будет удалена в будущих версиях grep, поэтому лучше предоставить способ в mygrep передавать параметры в grep, например, с помощью выделенного массива, если ваша оболочка поддерживает их:

mygrep() (
  pattern=$1; shift
  find "$@" -type d -path '*/app/lib/bower' -exec sh -c '
    printf >&2 "Warning: ignoring \"%s\" directory\n" "$@"
    ' sh {} + -prune -o -type f -exec \
    grep -IHne "${g[@]}" "$pattern" {} +
)

g=(-i --exclude-dir=.git); mygrep foo dir1 dir2

Или используйте --, чтобы указать mygrep, где параметры заканчиваются:

mygrep() (
  grep_options=()
  for i do
    grep_options+=("$i")
    shift
    [ "$i" != "--" ] || break
  done
  pattern=${1?нужен паттерн}; shift
  find "$@" -type d -path '*/app/lib/bower' -exec sh -c '
    printf >&2 "Warning: ignoring \"%s\" directory\n" "$@"
    ' sh {} + -prune -o -type f -exec \
    grep -H "${grep_options[@]}" "$pattern" {} +
)

mygrep -nI --exclude-dir=.git -- pattern dir1 dir2

(и убедитесь, что вы не передаете -- в качестве аргументов опции, например, если вы хотите исключить файлы --, используйте --exclude=--, а не --exclude --. Это также исключает использование, такое как mygrep -e pattern1 -e pattern2 -- dir или mygrep -f patternfile -- dir).

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

Для эффективной работы с командой grep в UNIX-подобных системах часто возникает необходимость игнорировать определенные директории, чтобы избежать ненужных совпадений или избыточного вывода. Рассмотрим подробный подход к этой задаче с учетом специфики проблемы, описанной выше.

Проблема

При регулярном использовании команды:

grep -rIn pattern directory

вы сталкиваетесь с необходимостью исключить директории, содержащие в пути такие части как app/lib/bower/lodash, app/lib/bower/paho-mqtt-js, и app/lib/bower/socket-io-client. Идеальной целью является игнорирование любого пути, содержащего app/lib/bower/.

Решение

Ваше первоначальное предложение:

alias grep='grep --exclude-dir={lodash,paho-mqtt-js,socket-io-client}'

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

Использование команды find для динамического исключения директорий

Обновленный метод с использованием find позволяет более гибко управлять исключаемыми директориями и предупреждает о пропусках:

mygrep() (
  pattern="$1"; shift
  find "$@" -type d -path '*/app/lib/bower' -exec sh -c '
    printf >&2 "Warning: ignoring \"%s\" directory\n" "$@"
    ' sh {} + -prune -o -type f -exec grep -IHne "$pattern" {} +
)

Пояснение:

  1. Использование find: Эта команда ищет директории по заданному шаблону (*/app/lib/bower) и исключает их с помощью -prune, тем самым сокращая область поиска для grep.

  2. Предупреждения: При исключении директории выводится предупреждение, что повышает информированность о проводимых действиях.

  3. Расширение GNU для grep: Использование флагов -I и -H помогает в улучшенной обработке выходных данных, позволяя игнорировать бинарные файлы и всегда выводить имя файла.

  4. Гибкость в параметрах grep: Предусмотрено использование переменных для передачи параметров в grep. Такой подход более устойчив к будущим изменениям, например, отказу от GREP_OPTIONS.

Опциональная конфигурация передаваемых параметров:

Если ваша оболочка поддерживает массивы, можно использовать конкретные массивы для передачи параметров:

g=(-i --exclude-dir=.git); mygrep foo dir1 dir2

Или с помощью специальной конструкции для передачи параметров:

mygrep -nI --exclude-dir=.git -- pattern dir1 dir2

Заключение

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

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

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