Точечное редактирование файлов: lineinfile и blockinfile

Рейтинг: 64.6% · 12 голосов
Подробный курс по Ansible с прицелом на экзамен RHCE EX294: установка и инвентарь, плейбуки, переменные и факты, Vault, циклы и условия, шаблоны Jinja2, роли и коллекции, Execution Environments и ansible-navigator, управление системами (диски, LVM, cron, SELinux, firewalld). Примеры на RHEL/Fedora. Актуально на 2026.
Ответить
Аватара пользователя
Maksim_DevOps
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Точечное редактирование файлов: lineinfile и blockinfile

Сообщение Maksim_DevOps »

Оглавление курса (47)
  1. Что такое Ansible и зачем он нужен: автоматизация без агентов
  2. Сертификация RHCE и экзамен EX294: что внутри и как готовиться
  3. Архитектура Ansible: control node, узлы, модули и плагины
  4. Установка Ansible на control node: dnf, pip и версии ansible-core
  5. Подготовка управляемых узлов: SSH, пользователь и sudo
  6. Инвентарь Ansible: hosts, группы и переменные
  7. Настройка Ansible: файл ansible.cfg и приоритеты конфигурации
  8. Host patterns и инструменты командной строки Ansible
  9. Ad hoc команды Ansible: быстрые задачи без плейбука
  10. Ansible playbook: что это такое и как устроен
  11. Структура плейбука: play, task, модули и переменные
  12. Запуск плейбуков: проверка, теги, ограничения и отладка
  13. Параллелизм и порядок выполнения: forks, serial, strategy
  14. Факты Ansible: сбор информации об узлах
  15. Переменные Ansible: типы, объявление и приоритет
  16. Регистрация результатов и специальные переменные
  17. Ansible Vault: шифрование паролей и секретов
  18. Организация инвентаря: group_vars, host_vars и вложенные группы
  19. Динамический инвентарь и инвентарные плагины
  20. Циклы в Ansible: loop, списки и словари
  21. Повтор задачи до условия: until, retries и delay
  22. Условия в Ansible: директива when и логика
  23. Jinja2 в Ansible: выражения, фильтры и подстановки
  24. Обработчики Ansible: handlers, notify и flush_handlers
  25. Обработка ошибок: failed_when, changed_when и ignore_errors
  26. Блоки в Ansible: block, rescue и always
  27. Управление файлами: модули file, copy, fetch и stat
  28. Архивы и сборка файлов: archive, unarchive, assemble
  29. Точечное редактирование файлов: lineinfile и blockinfile (вы здесь)
  30. Шаблоны Jinja2: модуль template и динамические конфиги
  31. Jinja2 продвинуто: фильтры, циклы, макросы и lookup
  32. Модули Ansible: ansible-doc и поиск нужного модуля
  33. Разработка собственного модуля Ansible на Python
  34. Роли Ansible и Ansible Galaxy: переиспользование
  35. Разработка роли Ansible: создание с нуля
  36. Зависимости ролей и requirements.yml
  37. Коллекции Ansible: ansible.posix, community и своя коллекция
  38. Execution Environments: контейнеры для запуска Ansible
  39. Сборка Execution Environment с ansible-builder
  40. ansible-navigator: запуск плейбуков в Execution Environment
  41. Управление SSH-ключами через Ansible: authorized_key
  42. Управление дисками: filesystem, mount и parted
  43. LVM через Ansible: тома, группы и расширение
  44. Планировщик задач: cron и systemd timers через Ansible
  45. Безопасность: hardening SSH и репозитории dnf/yum
  46. SELinux через Ansible: булевы, контексты и порты
  47. Сквозной проект и подготовка к экзамену EX294
Рано или поздно ты упрёшься в задачу: на сервере уже лежит конфиг, который ты НЕ хочешь переписывать целиком. Это /etc/ssh/sshd_config от вендора, /etc/hosts, /etc/sysctl.conf, /etc/fstab - файлы, где половина строк сгенерирована при установке, а тебе надо поменять или добавить буквально одну-две. Скопировать свой шаблон поверх? Опасно: затрёшь то, чего не знаешь. Дописать строку через shell-команду echo >> file? Так каждый прогон плейбука будет плодить дубликаты, и про идемпотентность можно забыть.

Вот здесь и выходят на сцену два модуля для хирургического редактирования файла ansible: ansible.builtin.lineinfile (одна строка) и ansible.builtin.blockinfile (управляемый блок строк). Плюс примкнувший к ним ansible.builtin.replace для замены по всему файлу. Разберём, как ими пользоваться так, чтобы повторный запуск ничего не ломал, и где они обманчиво опасны.

Как работает ansible lineinfile: regexp решает всё

Ключевая идея lineinfile - не "добавь строку", а "обеспечь, чтобы строка существовала в нужном виде". Модуль ищет в файле совпадение по regexp, и дальше логика такая:
  • совпадение нашлось - последняя совпавшая строка заменяется на значение line;
  • совпадения нет - строка из line добавляется (в конец файла или туда, куда укажешь через insertafter/insertbefore);
  • строка уже совпадает с line дословно - ничего не меняется, задача зелёная (ok, не changed).
Именно regexp даёт идемпотентность. Возьмём классику - выключить вход root по SSH:

Код: Выделить всё

- name: Запретить вход root по SSH
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#?\s*PermitRootLogin'
    line: 'PermitRootLogin no'
    validate: '/usr/sbin/sshd -t -f %s'
  notify: restart sshd
Regexp '^#?\s*PermitRootLogin' ловит и закомментированную строку (#PermitRootLogin prohibit-password), и уже раскомментированную, и с лишними пробелами. Любой из вариантов будет приведён к PermitRootLogin no. Запусти плейбук десять раз - после первого изменения остальные девять отработают как ok. Это и есть то, ради чего мы здесь.

Обрати внимание на validate. Параметр прогоняет твою команду на ВРЕМЕННОЙ копии файла перед тем, как заменить оригинал. %s - это плейсхолдер, куда Ansible подставит путь к временному файлу. Для sshd это sshd -t -f %s. Если конфиг невалиден - модуль падает с ошибкой, а боевой /etc/ssh/sshd_config остаётся нетронутым. На RHCE это буквально спасает: сломанный sshd_config и перезапущенный sshd - и ты потерял доступ к экзаменационной машине. Для sudoers используют validate: 'visudo -cf %s', для nginx - 'nginx -t -c %s'.

Изображение

insertafter, insertbefore и удаление строк

Когда строки в файле ещё нет и её надо поставить в конкретное место, добавляй insertafter или insertbefore. Значение - это тоже regexp (либо спецслова EOF/BOF - конец/начало файла).

Код: Выделить всё

- name: Добавить алиас в /etc/hosts после строки localhost
  ansible.builtin.lineinfile:
    path: /etc/hosts
    regexp: '\sdb01\.local$'
    line: '10.0.0.5 db01.local db01'
    insertafter: '^127\.0\.0\.1'
Важный нюанс: insertafter срабатывает ТОЛЬКО когда строки в файле ещё нет (по regexp не нашлось совпадения). Если строка уже есть, она правится на месте, insertafter игнорируется. Поэтому regexp и line должны быть согласованы между собой.

Удаление строки - это state: absent вместе с regexp. line при этом не нужен:

Код: Выделить всё

- name: Убрать старую запись из /etc/fstab
  ansible.builtin.lineinfile:
    path: /etc/fstab
    regexp: '^/dev/sdb1\s'
    state: absent
Удалятся ВСЕ строки, попавшие под regexp, так что пиши паттерн аккуратно.

ansible blockinfile: управляемый блок между маркерами

Когда надо вставить не одну строку, а кусок из нескольких (блок в /etc/hosts, секция конфига, набор переменных) - тут lineinfile неудобен. Берём ansible.builtin.blockinfile. Он оборачивает твой текст в пару маркеров-комментариев и при следующих запусках заменяет всё, что между ними. То есть блок остаётся "под управлением" Ansible: меняешь содержимое в плейбуке - меняется и кусок в файле.

Код: Выделить всё

- name: Управляемый блок sysctl для форвардинга
  ansible.builtin.blockinfile:
    path: /etc/hosts
    marker: "# {mark} ANSIBLE app-серверы"
    block: |
      10.0.0.11 app01.local app01
      10.0.0.12 app02.local app02
      10.0.0.13 app03.local app03
В файле появится:

Код: Выделить всё

# BEGIN ANSIBLE app-серверы
10.0.0.11 app01.local app01
10.0.0.12 app02.local app02
10.0.0.13 app03.local app03
# END ANSIBLE app-серверы
Плейсхолдер {mark} обязателен в marker - Ansible подставит туда BEGIN и END. Если в одном файле нужно несколько блоков, сделай marker уникальным для каждого (как тут - со словом "app-серверы"). Забудешь - второй блок затрёт первый, потому что маркеры совпадут. blockinfile тоже умеет insertafter/insertbefore и validate - всё как у lineinfile. Удалить блок целиком: state: absent с тем же marker.

replace, template и когда что выбирать

ansible.builtin.replace - это sed по всему файлу: заменяет ВСЕ вхождения regexp на replace. В отличие от lineinfile он не "обеспечивает одну строку", а правит все совпадения. Удобно для массовых замен:

Код: Выделить всё

- name: Поднять worker_connections во всех vhost
  ansible.builtin.replace:
    path: /etc/nginx/nginx.conf
    regexp: 'worker_connections\s+\d+'
    replace: 'worker_connections 2048'
    validate: 'nginx -t -c %s'
Теперь главное правило выбора. Если файл целиком твой - ты знаешь каждую его строку - НЕ используй lineinfile/blockinfile, бери ansible.builtin.template. Шаблон нагляднее, версионируется в git, и весь файл предсказуем. Точечные модули хороши ровно тогда, когда файл частично чужой (вендорский, сгенерированный пакетом) и трогать надо лишь фрагмент. Десять задач lineinfile подряд по одному файлу - верный признак, что пора переписать это в один template.

Маленькая пометка про дистрибутивы: пути отличаются. В RHEL/Fedora SSH-демон - sshd с конфигом /etc/ssh/sshd_config, в Debian/Ubuntu конфиг там же, но в свежих версиях ещё и /etc/ssh/sshd_config.d/*.conf. В RED OS и Astra Linux всё по схеме RHEL/Debian соответственно. Сами модули кросс-платформенны, меняются только пути и validate-команды.

Типичные грабли
  • regexp ловит не то. Спецсимволы regex (точка, скобки, слэши) надо экранировать. '^/dev/sda' и '^/dev/sda1' - разные вещи; незаякоренный паттерн '.local' совпадёт с серединой строки.
  • lineinfile меняет последнее совпадение, а не первое. Если под regexp попало несколько строк, правится последняя. Сужай паттерн якорями ^ и $.
  • Меняешь конфиг сервиса - не забыл validate и notify. Без validate можно положить sshd; без handler-перезапуска изменение не вступит в силу.
  • Несколько blockinfile в один файл с одинаковым marker. Дай каждому уникальную метку в {mark}.
  • insertafter не двигает существующую строку. Он работает только при ВСТАВКЕ новой. Хочешь переставить - сначала state: absent, потом добавить.
Мини-лаба

Руками на тестовой RHEL/Fedora-машине (или контейнере):
  • Напиши задачу lineinfile, которая ставит PermitRootLogin no в /etc/ssh/sshd_config с validate: '/usr/sbin/sshd -t -f %s'. Запусти дважды - убедись, что второй прогон ok, а не changed.
  • Намеренно подсунь битый line (например, PermitRootLogin maybe) - проверь, что validate ловит ошибку и файл не меняется.
  • Через blockinfile добавь блок из трёх записей в /etc/hosts с уникальным marker. Поменяй одну запись в плейбуке, прогони - блок обновился, дубликатов нет.
  • Через replace замени значение во всех вхождениях в тестовом конфиге и сравни поведение с lineinfile.
  • Сделай state: absent для строки и для блока - убедись, что они исчезают чисто.
Контрольные вопросы
  • За счёт какого параметра lineinfile остаётся идемпотентным и почему echo >> file так не умеет?
  • Что делает validate и почему без него опасно править sshd_config?
  • Зачем в marker модуля blockinfile нужен {mark} и что будет, если в одном файле два блока с одинаковым marker?
  • В каком случае правильнее взять template вместо lineinfile/blockinfile?
Итог

lineinfile правит одну строку по regexp, blockinfile - управляемый блок между маркерами, replace - все вхождения по всему файлу. Идемпотентность держится на грамотном regexp, а validate бережёт тебя от выстрела в ногу при правке конфигов сервисов. Но если файл целиком твой - не мельчи точечными задачами, бери template. На EX294 правка конфигов через lineinfile с regexp и validate - типовая задача, отработай её до автоматизма.
👍3 ❤️3 🔥1 😄 🤔1
Аватара пользователя
scott_brodie
Сообщения: 1
Зарегистрирован: 11 май 2026, 01:40

Re: Точечное редактирование файлов: lineinfile и blockinfile

Сообщение scott_brodie »

Спасибо, наконец дошло почему мои echo >> в shell плодили дубли. Перевёл правку sshd_config на lineinfile с regexp - второй прогон стал ok, красота. validate реально спас один раз, опечатался в line и плейбук просто упал вместо того чтобы убить мне ssh.
👍1 ❤️ 🔥1 😄 🤔2
Аватара пользователя
AsyncUser
Сообщения: 1
Зарегистрирован: 31 май 2026, 05:02

Re: Точечное редактирование файлов: lineinfile и blockinfile

Сообщение AsyncUser »

Вопрос по blockinfile: а если я руками внутри маркеров что то поправлю на сервере, при следующем прогоне Ansible это затрёт обратно? Правильно понимаю что блок между BEGIN и END он считает целиком своим?
👍1 ❤️2 🔥 😄 🤔
Ответить
← Предыдущая глава
Архивы и сборка файлов: archive, unarchive, assemble
Следующая глава →
Шаблоны Jinja2: модуль template и динамические конфиги

Все главы курса «Ansible: автоматизация и подготовка к RHCE (EX294)»

Поделиться темой: ✈ Telegram VK

Вернуться в «Ansible: автоматизация и подготовка к RHCE (EX294)»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость