Вопрос или проблема
Ежедневное использование:
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" {} +
)
Пояснение:
-
Использование
find
: Эта команда ищет директории по заданному шаблону (*/app/lib/bower
) и исключает их с помощью-prune
, тем самым сокращая область поиска дляgrep
. -
Предупреждения: При исключении директории выводится предупреждение, что повышает информированность о проводимых действиях.
-
Расширение GNU для
grep
: Использование флагов-I
и-H
помогает в улучшенной обработке выходных данных, позволяя игнорировать бинарные файлы и всегда выводить имя файла. -
Гибкость в параметрах grep: Предусмотрено использование переменных для передачи параметров в
grep
. Такой подход более устойчив к будущим изменениям, например, отказу отGREP_OPTIONS
.
Опциональная конфигурация передаваемых параметров:
Если ваша оболочка поддерживает массивы, можно использовать конкретные массивы для передачи параметров:
g=(-i --exclude-dir=.git); mygrep foo dir1 dir2
Или с помощью специальной конструкции для передачи параметров:
mygrep -nI --exclude-dir=.git -- pattern dir1 dir2
Заключение
Предложенное решение посредством создания функции mygrep
обеспечивает более гибкую и поддерживаемую реализацию задачи по исключению ненужных директорий в поиске, одновременно сохраняя возможность обработки широкого спектра опций. Такой подход экономит время и предотвращает необходимость регулярного пересмотра списка исключений, делая процесс более управляемым и автоматизированным.