Найдите команды + Sed + Grep для проверки замен

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

Пытаюсь протестировать, что мой sed работает, фильтруя файлы снова с помощью grep.

Могут быть трудные, но лаконичные способы, но я предпочел бы какой-то идиоматический способ запомнить.

Это не срабатывает:

find src -type f -name "*.py" -not -name "*.pyc" -exec sed -E "" "s/basicConfig/setLevel/g" {} + -exec grep "setLevel" {} +

Это, похоже, не срабатывает, потому что grep ищет в немодифицированных файлах, а не в измененном потоке.

Можно использовать -nE, чтобы убрать раздражающий (в данном случае) вывод sed, но тогда все равно будет искать в оригинальных файлах.

Если я передам вывод (просто используя -E), он все равно ничего не находит.

Я думаю, что возможно, find не поддерживает каналы, так как предоставляет -exec.

Следующим шагом было попробовать модификацию предложения из поста на SO, который использует оболочку:

find src -type f -name "*.py" -not -name "*.pyc" -exec sh -c "sed -E '' 's/basicConfig/setLevel/g' | grep 'setLevel'" {} +

Но я получаю: sed: s/basicConfig/setLevel/g: Нет такого файла или каталога

Использую MacOS, но не стесняйтесь отвечать для любого UNIX.

Это сработало:

find src -type f -name "*.py" -not -name "*.pyc" -exec sh -c "sed 's/basicConfig/setLevel/g' {} | grep setLevel" \;

Или с -i, но с ним не следует тестировать

find src -type f -name "*.py" -not -name "*.pyc" -exec sh -c "sed -i '' 's/basicConfig/setLevel/g' {} | grep setLevel" \;

'' нужно, чтобы сказать sed не создавать резервные файлы в MacOS, поэтому это не нужно с -E (который упоминается в посте и на самом деле был для другого случая и был скопирован.)

В этих случаях {} помещалось там, где должны быть имена файлов, и он заканчивается \;.

Если вы хотите передать вывод find и все команды, которые он выполняет, просто сделайте:

find src -type f -name '*.py' ! -name '*.pyc' \
  -exec sed s/basicConfig/setLevel/g {} + |
  grep setLevel

Но если вы хотите печатать только строки, которые изменяются, просто скажите sed об этом, нет необходимости в grep:

find src -type f -name '*.py' ! -name '*.pyc' \
  -exec sed -n s/basicConfig/setLevel/gp {} +

-E включают расширенные регулярные выражения, но вы не используете никаких операторов регулярных выражений, ни расширенных, ни обычных.

Этот лишний пустой аргумент, который вы добавляете, не имеет смысла. Он в конечном итоге обрабатывается как код sed, и тогда s/basicConfig/setLevel/g становится файлом для поиска.

С реализацией sed на FreeBSD, как на macos, вы могли столкнуться с:

sed -i '' s/foo/bar/g file

Там '' является аргументом суффикса резервной копии опции -i, что означает, что sed должен редактировать файл на месте без резервной копии оригинала.

Если вы уберете опцию -i, вам также нужно убрать '', который идет с ней.

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

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

1. Проблема

Вы хотите использовать sed для выполнения замены в файлах и затем проверить, была ли эта замена выполнена, с помощью grep. Однако сложность заключается в том, что find как команда не поддерживает прямую передачу выходных данных sed в следующую команду, как это делается в конвейере с использованием символа |.

2. Решение

Существует несколько способов решить эту задачу. Рассмотрим наиболее эффективные и легко запоминающиеся.

Вариант 1: Использование -exec sh -c

Этот метод позволяет выполнить несколько команд в рамках одной операции find, передавая выходные данные sed в grep.

find src -type f -name "*.py" -not -name "*.pyc" -exec sh -c "sed 's/basicConfig/setLevel/g' {} | grep setLevel" \;
  • Пояснение:
    • -exec sh -c позволяет запустить оболочку, где мы выполняем команды sed и grep.
    • {} — это подстановка текущего файла, найденного командой find.
    • \; завершает команду -exec.

Вариант 2: Прямое использование -exec

Если вы хотите сразу вывести только изменённые строки без использования grep, можно сделать так:

find src -type f -name "*.py" -not -name "*.pyc" -exec sed -n 's/basicConfig/setLevel/gp' {} +
  • Пояснение:
    • -n — подавляет стандартный вывод sed, а p (print) печатает только те строки, которые были изменены.

3. Заметки о sed

Обратите внимание, что если вы используете -i для редактирования файлов на месте, в macOS необходимо указать пустую строку после -i, чтобы не создавать резервные копии:

find src -type f -name "*.py" -not -name "*.pyc" -exec sed -i '' 's/basicConfig/setLevel/g' {} +
  • Важно: Не рекомендуется использовать опцию -i для тестирования, так как она изменяет оригинальный файл. Вместо этого используйте первый вариант, чтобы проверить изменения, не затрагивая исходные файлы.

4. Рекомендации по использованию

  • Тестируйте команды на небольшом количестве файлов, чтобы убедиться в их правильности перед массовым запуском.
  • Чистота кода: Избегайте лишних аргументов и двойных кавычек в командах sed, если они не нужны, чтобы не запутаться в синтаксисе.
  • Используйте расширенные регулярные выражения: При необходимости можно добавить флаг -E, чтобы активировать расширенные регулярные выражения, однако в данном случае этого не требуется, так как используются базовые выражения.

Заключение

Комбинация команд find, sed и grep может показаться сложной, однако с использованием предложенных выше методов вы сможете эффективно находить и заменять текст в файлах, а также проверять изменения. Практика поможет вам лучше запомнить эти команды и их синтаксис, что повысит вашу продуктивность в работе с Linux иUnix-системами.

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

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