Про офигительные циркули. Порой бывает устанавливаешь какую-нибудь софтину на linux, а в придачу с ней идет огромный example конфиг. Этим конфигом можно пользоваться по дефолту, либо тонко настраивать. Например, конфиг от php.ini весит 80 килобайт. И больше половины в этом конфиге - комментарии и шляпа.

А хочется сделать из этого конфига простенький шаблон например для ansible, но без лишнего мусора. Чтобы было основное, что позволит софтине вообще запуститься (пути, логи, сокеты и т.п.). Руками выкашивать 60-70 килобайт, то еще занятие.

Но что если сделать свой собственный маленький парсер? Который выкосит все ненужное и оставит необходимый минимум. Да, прям на bash! Погнали зажигать!

Для примера будем работать с тем же файлом php.ini и приведем его в юзер-френдли вид.

Накидываем скрипт:

#!/bin/bash

sep=$2

while IFS= read -r var
do
  [[ $var =~ ^$sep.* ]] || [[ ! $var =~ ' ' ]] && continue
  echo "$var" >> $1.tpl
done < $1

Запускаем так:

./script.sh php.ini ";"

Передаем 2 параметра. Первый = имя файла-конфига, который будем читать и парсить. Второй = символ, которым комментируются строки в этом файле.

В моем случае комментарии в файле идут после «;» символа. Обращаем внимание, что второй параметр передаем в кавычках. Если передать напрямую, то оболочка bash не поймёт что от нее хотят и выпадет в panic.

Разбираем скрипт:

Присваиваем переменной sep, символ, который передали вторым параметром $2. У меня это символ «;».

Далее идет цикл, который построчно читает файл php.ini переданный в первом параметре $1 при запуске скрипта. Тут универсально, можешь любой файл передать, скрипт его сам схавает как нужно.

IFS= разделяет строку с использованием символа в качестве значения

Ну и логика цикла:

Если первый символ равен символу «;», который уже лежит в переменной sep ИЛИ первый символ равен пустой строке, ТО передаем управление команде continue, которая проигнорирует запись в output файл. И так по кругу, пока не закончится файл.

Команда continue пропускает оставшиеся команды внутри тела цикла для текущей итерации и передает управление программой к следующей итерации цикла.

Символ || означает = ИЛИ

ВО ВСЕХ ДРУГИХ СЛУЧАЯХ, происходит запись в output файл, в котором будут содержаться только необходимые для работы параметры.

На выходе получится 2х килобайтный файл php.ini.tpl, без комментариев и прочего шлака. Чистый как слеза.

Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
80 килобайт vs 2 килобайта! Ха! Разница ощутима, теперь можно сделать шаблончик для ansible/puppet/chef.

В своем скрипте я использую простые регулярные выражения. ДА! В bash это можно делать через символы «=~».

$var =~ ^$sep.*
^ = соответствует началу текстовой строки
$sep = символ с помощью которого комментируют строки
.* = оставшийся кусок строки

А можно еще другим способом определять начинается ли строка с определенного символа. Но конкретно с разделителями «;»/«#» это будет работать некорректно.

[[ $var = Y* ]] && echo "String start with Y"

В примере выше, происходит проверка, является ли первый символ в строке символом «Y» и если да, то пезда, выводится соответствующее сообщение. Регулярок тут нет, чисто «*» правит балом.

Такие дела. И без применения всяких sed/бред/винегрет. Нативно, на bash, даже с регулярками научились взаимодействовать, а регулярки развязывают на многое руки. В пределах разумного, не нужно brainfuck создавать.

Brainfuck — один из эзотерических языков программирования, придуман Урбаном Мюллером

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

Завтра сделаем паузу, а в четверг и в пятницу еще немного поэкспериментируем. Давай! Пока-пока!