Форум русскоязычного сообщества Ubuntu


Следите за новостями русскоязычного сообщества Ubuntu в Twitter-ленте @ubuntu_ru_loco

Автор Тема: bash двойная подстановка -- обработка $(program $ARG), подстановка через sed  (Прочитано 2072 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн DarkArchangel

  • Автор темы
  • Участник
  • *
  • Сообщений: 126
    • Просмотр профиля
Есть несколько скриптов, что-то делающих при поднятии/опускании интерфейсов. Думал по-быстрому собрать некий мастер-конфиг, при изменении параметров просто вписывать в его переменные и генерировать по образцам новые скрипты с нужными переменными.
Пример.
Файл с переменными для всего и циклом для генерации нового из имеющихся "идеальных"
master_with_variables.sh
(Нажмите, чтобы показать/скрыть)


ideal_cfg_to_generate.sh
(Нажмите, чтобы показать/скрыть)

Сгенерированый файл
new_generated_file.sh
(Нажмите, чтобы показать/скрыть)
#вместо ожидаемого IP_EXTERN_RESOURCE=$(nslookup ya.ru | tail -n 2 | awk '{print $2}')

Как-то запретить eval выполнять команды $(...) можно? Или только в "мастер-скрипте" все переменные со значениями пихать в массив, при получении строки -- проверять, что из переменных там вызывается и подменять тем же sed на имеющееся в массиве значение?


Решено с помощью valrust в следующих сообщениях.

АП. На случайных скриптах работает кривовато, где-то eval как-то всё же срабатывает. Попробую через HERE DOCUMENTS, может получится обработке пачки файлов приписать.
UP1. С ручной подстановкой через grep-sed вроде сносно отрабатывает.

В одной со скриптом папе создать master_cfg, складывать туда скрипты-образцы с воссозданием структуры ФС внутри папки, с запросом вызова значения переменной вместо фиксированного значения (например вместо address=192.168.0.1 -- address=$ADDRESS_FROM_MASTER_SCRIPT).
В мастер-скрипте в массиве указать переменные и их значения, которые будут подменяться в скриптах-образцах, например ADDRESS_FROM_MASTER_SCRIPT=192.168.0.1
В директории со скриптом же будет создан temp_cfg, все изменения будут производиться уже в ней.
Основной файл текстом здесь и текстом во вложении (переименовать txt в sh)
(Нажмите, чтобы показать/скрыть)
Как основной скрипт работает, что вызывает
(Нажмите, чтобы показать/скрыть)

---
Строки для поисковика
bash eval eval, bash double substitution, bash evaluate, eval экранировать, eval экранирование, Here documents, EOF, generate config, generate config files, script, bash script, bash scripting. подстановка значения переменной, bash substitute variables via sed, bash substitution sed grep, bash manual variable substitution, config generation, cfg generation, config cfg generator generation create
« Последнее редактирование: 31 Января 2022, 11:05:20 от DarkArchangel »
asus p8h67/intel xeon e3-1230v2+Scythe Mugen/8GB PC12600/AMD Radeon 6770, open-source driver/2tb Hitachi deskstar 7200 rpm + Goodram Iridium 120G, Lubuntu 22.04

Оффлайн valrust

  • Активист
  • *
  • Сообщений: 364
    • Просмотр профиля
В файле ideal_cfg_to_generate.sh нужно символы $ экранировать обратным слешем \$

Или можно используя тип перенаправления "Here Documents" шаблон вставить в мастер-скрипт.
WANIF_MASTER_VAR=eth0
WANIF_IP_MASTER_VAR=172.10.23.11
SOME_EXTERNAL_RES_MASTER_VAR=ya.ru

cat >new_generated_file.sh <<EOF
WANIF=$WANIF_MASTER_VAR
WANIF_IP=$WANIF_IP_MASTER_VAR
IP_EXTERN_RESOURCE=\$(nslookup $SOME_EXTERNAL_RES_MASTER_VAR | tail -n 2 | awk '{print \$2}')
EOF


Оффлайн DarkArchangel

  • Автор темы
  • Участник
  • *
  • Сообщений: 126
    • Просмотр профиля
Valrust
Спасибо, почти как написал, помогло.
Делать без доп. изменений cat ./ideal_cfg_to_generate.sh <<EOF | while read STR... -- ругается на неожиданный конец файла (хоть добавлять EOF в конце ideal_cfg_to_generate.sh, хоть нет), но выводит что требуется. Не очень подоходит, потому что шаблонов может быть много, в одном мастер-скрипте будет просто неудобно ориентироваться.
Если экранировать только $, то бинарники, которые дальше в реальных файлах встречаются, всё равно запускаются. Добавил в начале  ideal_cfg_to_generage.sh пробел и обратный слеш.
Т.е.
(Нажмите, чтобы показать/скрыть)

Добавлю готовый скрипт сюда и в первое сообщение. Операции записи в корневую ФС заменени на "покажи команду".
« Последнее редактирование: 28 Января 2022, 14:41:14 от DarkArchangel »
asus p8h67/intel xeon e3-1230v2+Scythe Mugen/8GB PC12600/AMD Radeon 6770, open-source driver/2tb Hitachi deskstar 7200 rpm + Goodram Iridium 120G, Lubuntu 22.04

Оффлайн DarkArchangel

  • Автор темы
  • Участник
  • *
  • Сообщений: 126
    • Просмотр профиля
Не работает как надо, кажется быстрее руками менять.
Только опять прям на ровном месте спотыкаюсь.
Хочу
Запихнуть переменные со значениями в массив, выдрать из массива названия переменных, сформировать из названий переменных строку поиска для grep, добавив в начале \\\$ перед каждым именем и \| -- после. Получится длинное ищи "$VAR1 или $VAR2 или $VARN", выведи только совпадения. Потом с этими совпадениями уже что-то делать.
Получается.
...что греп по сформированной строке не возвращает ничего.

(Нажмите, чтобы показать/скрыть)

Так возвращает только ARGS found in given string

Меняем в последней команде процедуры на паттерн для поиска руками (скопипастил из сформированного скриптом куска)
echo ARGS found \in given string $(echo $@ | grep -E -oh \\\$IF_WAN_YARNET_MASTER\|\\\$IF_PPP_MASTER )-- получаем
ARGS found in given string $IF_WAN_YARNET_MASTER $IF_PPP_MASTER
То же самое если просто вписать в переменную и скормить её грепу
i=\\\$IF_WAN_YARNET_MASTER\|\\\$IF_PPP_MASTER
echo ARGS found \in given string $(echo $@ | grep -E -oh  $i )

Что я делаю не так?



Пользователь добавил сообщение 30 Января 2022, 21:17:17:
Сам спросил -- сам ответил.
оно по-разному возвращает в команду паттерны. Из обработанной седом переменной —- ровно как написал, с кучей экранирующих слешей и как положено, как при ручном вводе regexp для grep. И не работает.
А из текстового паттерна или переменной, куда руками с терминала этот паттерн скопипастил — с меньшим количеством экранирующих слешей. И работает.
Поиск — сначала echo $VAR_FROM_SED | md5sum, echo \\\$TEXT_PATTERN | md5sum
Потом то же самое, но в hexdump -c
« Последнее редактирование: 30 Января 2022, 21:17:17 от DarkArchangel »
asus p8h67/intel xeon e3-1230v2+Scythe Mugen/8GB PC12600/AMD Radeon 6770, open-source driver/2tb Hitachi deskstar 7200 rpm + Goodram Iridium 120G, Lubuntu 22.04

Оффлайн valrust

  • Активист
  • *
  • Сообщений: 364
    • Просмотр профиля
Используйте для генерации новых файлов из простых шаблонов конструкцию
cat <<EOF >newfile.sh
here-document
EOF
где, here-document это и есть простой шаблон состоящий из множества строк.

Первое перенаправление <<EOF говорит bash, что нужно на стандартный вход команде cat подать строки которые идут начиная со следящей строки после команды и до строки, которая состоит из слова EOF.

Но перед тем, как отправить на стандартный вход команды cat в этих строках bash выполняет раскрытие переменных $VAR или ${VAR} и арифметических выражений $(( expression )), а так же выполняет подстановку команд $(command) или `command`.

Если, нужно, что бы $ и ` не раскрывались, а остались в тексте в том виде как они есть, то их нужно экранировать обратным слешем \.

Второе перенаправление >newfile.sh перенаправляет стандартный выход команды cat в файл newfile.sh.

Пример для генерации я уже приводил выше
(Нажмите, чтобы показать/скрыть)

Оффлайн DarkArchangel

  • Автор темы
  • Участник
  • *
  • Сообщений: 126
    • Просмотр профиля
valrust
Ознакомился с парой отдельных топиков по HERE DOCUMENTS, вроде нормально должно работать в любом месте скрипта, но не работает.
Т.е. когда там дальше, после любой открывающей-закрывающей последовательности, что-то ещё есть -- ругается на неожиданный конец файла и ничего дальше не выполняет. По итогу забил и делаю все подстановки через egrep/sed.

master.sh
(Нажмите, чтобы показать/скрыть)

Причешу основной файл -- добавлю в последнее и первое сообщение ветки.

Основной файл
(Нажмите, чтобы показать/скрыть)

Как работает
(Нажмите, чтобы показать/скрыть)
« Последнее редактирование: 31 Января 2022, 10:56:16 от DarkArchangel »
asus p8h67/intel xeon e3-1230v2+Scythe Mugen/8GB PC12600/AMD Radeon 6770, open-source driver/2tb Hitachi deskstar 7200 rpm + Goodram Iridium 120G, Lubuntu 22.04

Оффлайн valrust

  • Активист
  • *
  • Сообщений: 364
    • Просмотр профиля
ругается на неожиданный конец файла
Если речь про такую ошибку
test.sh: line 9: warning: here-document at line 3 delimited by end-of-file (wanted `EOF')
То это значит, что в строке EOF есть пробелы или табуляция. А по правилам в этой строке должен быть только EOF, т.е. строка должна начинаться с EOF и заканчиваться, других символов в финальной строке не должно быть.


Оффлайн DarkArchangel

  • Автор темы
  • Участник
  • *
  • Сообщений: 126
    • Просмотр профиля
valrust
Классические примеры всё же работают. Т.е. такое файло
(Нажмите, чтобы показать/скрыть)
возвращает что нужно
(Нажмите, чтобы показать/скрыть)
up. Перечитал. Должно же вернуть
(Нажмите, чтобы показать/скрыть)
это же документ, не?


А вот при попытке натянуть сову на глобус
(Нажмите, чтобы показать/скрыть)

получаем "неожиданный конец"
(Нажмите, чтобы показать/скрыть)

При этом если натравить file_cat_eval_eval.sh
(Нажмите, чтобы показать/скрыть)
на специально сформированный файл heredoc_file.sh
(Нажмите, чтобы показать/скрыть)
оно всё равно что-то пытается выполнить в строке с echo и grep
(Нажмите, чтобы показать/скрыть)

В целом концепция подходит для решения конкретной задачи не с меньшим количеством оговорок, чем через sed/grep менять. Возможно питоном (как компетентный товарищ рекомендовал), сями или иными ЯП оно вообще решается проще и красивей, но это уже отдельная тема.





« Последнее редактирование: 31 Января 2022, 17:28:57 от DarkArchangel »
asus p8h67/intel xeon e3-1230v2+Scythe Mugen/8GB PC12600/AMD Radeon 6770, open-source driver/2tb Hitachi deskstar 7200 rpm + Goodram Iridium 120G, Lubuntu 22.04

Оффлайн ALiEN

  • Администратор
  • Старожил
  • *
  • Сообщений: 6837
  • 20% Cooler
    • Просмотр профиля
Думал по-быстрому собрать некий мастер-конфиг, при изменении параметров просто вписывать в его переменные и генерировать по образцам новые скрипты с нужными переменными.
Кажется мне, вы вообще выбрали неверный подход, оттого и сложности.
Опишите вашу первоначальную задачу словами, без bash.
Цитировать
что-то делающих при поднятии/опускании интерфейсов
???
🖥 AsRock B550M Pro4 :: AMD Ryzen 5 3600 :: 16 GB DDR4 :: AMD Radeon RX 6600 :: XFCE
💻 ACER 5750G :: Intel Core i5-2450M :: 6 GB DDR3 :: GeForce GT 630M :: XFCE

Оффлайн valrust

  • Активист
  • *
  • Сообщений: 364
    • Просмотр профиля
DarkArchangel, Вы на BASH смотрите как на обычный язык программирования, но это не правильный подход. BASH читает каждую строку скрипта далее преобразует её по определённым правилам, а потом выполняет получившеюся команду.

Если разбирать этот пример,
line1=aaa
cat <<HEREDOC
echo line1
echo $line1
HEREDOC
echo line1 var is $line1
то вот, что будет делать BASH:

Прочитав строку
line1=aaa
BASH создаст переменную с именем line1 и сохранит в ней строку "aaa".

Прочитав строку
cat <<HEREDOC
BASH создаст дочерний процесс в котором продолжит выполнение обработку скрипта, а основной процесс  BASH уйдет в ожидание завершения дочернего процесса.

В дочернем процессе BASH создаст временный файл. В этот временный файл скопирует все строки, которые идут после строки с командой cat и до строки со словом HEREDOC. При копировании во временный файл BASH будет обрабатывать каждую строку.

Встретив при копировании строку
echo $line1
BASH преобразует эту строку используя раскрытие переменной, так как в ней есть специальный символ $. Bash будет считать, что после $ идет имя переменной и подстроку $line1 заменит на значение переменной line1, т.е. на строку aaa.

Когда все строки будут скопированы (обработаны), то во временном файле будут следующие строки
echo line1
echo aaa


Когда временный файл будет готов, дочерний процесс с BASH подключит этот файл к стандартному входу. А потом внутри дочернего процесса будет выполнена замена исполняемого кода на код из файла /usr/bin/cat.

Так как стандартный вход дочернего процесса связан с временным файлом, то cat выведет его содержимое на стандартный выход и завершит работу. И завершиться дочерний процесс.

Дальше продолжит работу основной процесс BASH, который продолжит обработку скрипта после строки HEREDOC.

Прочитав строку
echo line1 var is $line1
BASH выполнит раскрытие переменной и получит такую строку
echo line1 var is aaa
и выполнит внутреннею команду echo, которая напечатает свои аргументы на стандартный выход.

Оффлайн ALiEN

  • Администратор
  • Старожил
  • *
  • Сообщений: 6837
  • 20% Cooler
    • Просмотр профиля
Уточню - bash вообще ни разу не язык программирования, а очень мощный командный интерпретатор.
🖥 AsRock B550M Pro4 :: AMD Ryzen 5 3600 :: 16 GB DDR4 :: AMD Radeon RX 6600 :: XFCE
💻 ACER 5750G :: Intel Core i5-2450M :: 6 GB DDR3 :: GeForce GT 630M :: XFCE

Оффлайн DarkArchangel

  • Автор темы
  • Участник
  • *
  • Сообщений: 126
    • Просмотр профиля
valrust
в тонкости обработки команд не вдавался, от этого тоже бывают грабли. Формально разницу между "интерпретатор/транслятор/компилятор" знаю, точно же указать на особенности работы каждого из вариантов в решении конкретной задачи не смогу. И соответственно воспринимаю как среду, могущую решить часть моих небольших задач.
Разбор примера постараюсь присвоить и запомнить, спасибо.
ALiEN175
Задача "без баш" самом первом сообщении -- подменять переменные в пачке разнообразных скриптов-образцов.
Решена в итоге через grep/sed.
Про "bash это ЯП" -- поминал только в контексте python/c/other, bash к ним не причислял.
И да, способ решения скорее всего не самый эффективный, но на чём уже сделал -- на том сделал. Не в продакшн, чай, миллионы скриптов с тысячами переменных обрабатывать.

Вопросов по теме пока больше нет. Возможно кому-то ещё пригодится.
Спасибо за помощь
asus p8h67/intel xeon e3-1230v2+Scythe Mugen/8GB PC12600/AMD Radeon 6770, open-source driver/2tb Hitachi deskstar 7200 rpm + Goodram Iridium 120G, Lubuntu 22.04

Оффлайн ALiEN

  • Администратор
  • Старожил
  • *
  • Сообщений: 6837
  • 20% Cooler
    • Просмотр профиля
подменять переменные в пачке разнообразных скриптов-образцов.
для этого существует возможность передавать скрипту аргументы.

И нет, это не первоначальная задача. Вопрос (и собственно, ответ) находится чуть дальше: зачем подменять переменные в пачке разнообразных скриптов-образцов?
Забудьте про переменные, подстановку и скрипты. Какая поставлена задача?

Пользователь добавил сообщение 31 Января 2022, 21:45:57:
Если вышесказанное сложно для понимания, вот простой и понятный пример:

Как перезапустить сетевой интерфейс при обрыве связи? Планируется использование на разных машинах, где имена интерфейсов могут не совпадать.
« Последнее редактирование: 31 Января 2022, 21:45:57 от ALiEN175 »
🖥 AsRock B550M Pro4 :: AMD Ryzen 5 3600 :: 16 GB DDR4 :: AMD Radeon RX 6600 :: XFCE
💻 ACER 5750G :: Intel Core i5-2450M :: 6 GB DDR3 :: GeForce GT 630M :: XFCE

Оффлайн DarkArchangel

  • Автор темы
  • Участник
  • *
  • Сообщений: 126
    • Просмотр профиля
ALiEN175
Если так посмотреть, то надо, чтоб работало, настроил и забыл, а если понадобилось переехать на другую физичекую систему или карты поменять -- быстро переконфигурять. Но для этого уже и баш необязателен, да и стационарник с убунтой -- "возьми пару микротиков hap ac^2, настрой оба, один отложи, если первый сгорит. Ну и какой-нибудь либо готовый NAS, либо на каком-нибудь intel nuc собрать и synology накатить". Можно даже этим не заниматься, а заплатить компетентному специалисту.
Или не заниматься -- пользовать как есть пока не помрёт, как всё -- туда ему и дорога. Ничего прям важного не висит. И о5 ни стационарник, ни полноценный линукс, ни сервисы сетевые, руками настроенные и поднятые, не нужны.

Если выше слишком сложно, то "Всё тлен, ничего неважно, и костыльный генератор скриптов тоже -- всё просто временные необязательные развлечения, результаты которых развеются прахом вместе со мной. Мы все умрём".
asus p8h67/intel xeon e3-1230v2+Scythe Mugen/8GB PC12600/AMD Radeon 6770, open-source driver/2tb Hitachi deskstar 7200 rpm + Goodram Iridium 120G, Lubuntu 22.04

 

Страница сгенерирована за 0.079 секунд. Запросов: 25.