sed подставил старое значение вместо амперсанда: отделяем replacement от шаблона

В конфигурационном фрагменте нужно заменить название поставщика на R&D. Команда sed выполняется без ошибки, но в результате появляется ROLD_VENDOR D или другое неожиданное сочетание со старым текстом. Причина в том, что правая часть s-команды тоже имеет специальный синтаксис. Амперсанд означает весь найденный фрагмент.

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

Начнём с неизменяемого исходника

Ниже вход хранится в source.conf, а новый вариант — в candidate.conf. Исходный файл остаётся доступен для сравнения. Запускайте пример в отдельном каталоге.

printf '%s\n' 'vendor=OLD_VENDOR' 'mode=preview' > source.conf
sed 's|OLD_VENDOR|R\&D|g' source.conf > candidate.conf
diff -u source.conf candidate.conf

В diff будет изменена только строка vendor: новое значение R&D. Обратная косая черта перед & просит sed вставить буквальный амперсанд. Разделитель | выбран, чтобы пути с обычным / было легче читать; это не универсальное экранирование. Если в данных встретится |, его тоже придётся учитывать.

diff возвращает 1, когда файлы различаются. Для предварительного просмотра это ожидаемый результат, а не ошибка подготовки кандидата. В скрипте с set -e такой вызов тоже требует осмысленной обработки статуса. Не объединяйте проверку ожидаемых различий с разрешением изменять реальный файл одной непрозрачной цепочкой.

Фиксированная и произвольная замена — разные задачи

Когда обе стороны выражения написаны автором, необходимые экранирования видны в коде. Когда новое значение приходит из переменной, простое sed "s|TOKEN|$value|g" уже ненадёжно. В value могут находиться &, обратная косая черта, выбранный разделитель и перевод строки. Каждый случай меняет разбор выражения.

Для ограниченного однострочного значения можно последовательно экранировать специальные символы, но это уже отдельная функция с тестами. Если требуется менять структурированный конфиг, лучше использовать его парсер или шаблонизатор: тогда имя поля и значение передаются как данные. Особенно это важно для JSON, где кавычки и переводы строк имеют собственные правила.

Левая часть s-команды тоже остаётся регулярным выражением. Замена буквального значения v1.2 через незакрытую точку может выбрать v1X2. Починить только амперсанд справа недостаточно, если искомый текст тоже произвольный. Для фиксированного маркера вроде OLD_VENDOR такой неопределённости нет; именно поэтому пример использует явный токен шаблона.

Проверим, сколько мест изменилось

Флаг g заменяет все совпадения внутри каждой строки. Без него меняется только первое совпадение на строке, но sed всё равно проходит все строки файла. Если в конфиге должно существовать ровно одно место для маркера, проверьте это до подстановки. Иначе дублированный фрагмент шаблона может привести к правке нескольких параметров сразу.

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

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

В программе Linux и Bash изучаются безопасные скрипты и корректный quoting. Откройте программу и свяжите обработку текста с полноценной процедурой изменения: подготовкой значения, проверкой результата и понятной остановкой при ошибке.

Ещё по теме

Продолжить на практике

  • Linux и Bash для DevOps-инженеров ↗

    Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.