Не получается использовать :put для вывода содержимого глобальной переменной внутри скрипта. В терминале cli всё работает нормально, и видно, что глобальная переменная меняется из скрипта, но при запуске скрипта в консоли никакого вывода нет. Использую версию 6.43.7 и последнюю Winbox. Искал решение на форуме и в гугле — без успеха. Буду признателен за советы.
stuartpbb
Guest
0
17.03.2022 02:35:00
Могли бы вы обновить документацию, чтобы это отражалось? Я только что столкнулся с той же проблемой и был уверен, что это баг, пока не прочитал это.
Jotne
Guest
0
18.03.2022 13:24:00
Когда у тебя есть скрипт, который запускается, скажем, ровно в 00:00 каждую ночь, где ты ожидаешь увидеть вывод :put? У тебя круглосуточно открыта терминальная сессия, которая ждёт этот вывод? Вот почему у нас есть :log, который отправляет вывод в лог или syslog. Данные также можно отправлять по email, ftp, http, мигать светодиодом +++ (гугли email, telegram +++++). Я использую :put только когда отлаживаю скрипт, чтобы в терминале увидеть, что там происходит во время теста.
stuartpbb
Guest
0
18.03.2022 17:56:00
Вау… Я не ожидал такой реакции от поклонников Mikrotik. Было бы полезнее сначала попытаться выяснить детали, прежде чем бросаться с обвинениями и говорить, что человек полностью неправ, просто за то, что он попросил обновить документацию. Надо было и мне чуть яснее сформулировать. Моя проблема не с планировщиком задач, а с примерно таким скриптом и тем, что :put ведёт себя не так, как ожидается:
{ :local data "this is a test";
{ :local foo [/system routerboard get board-name]; :set data ($data . "\n" . $foo); :put "debug: added to data: $foo"; }
Я проверял это на RouterOS v6 и v7: оба выведут первую команду :put, но вторую нет. Моя версия — внутренний блок кода (используемый, чтобы переменная :local foo была видна только внутри него) перенаправляет вывод так, что :put после fetch просто не появляется в консоли. В документации я ничего не нашёл, что объясняло бы такое поведение, поэтому и попросил обновить документацию, чтобы объяснить случаи, когда :put ведёт себя не так, как логично ожидать (и как работают print в других языках сценариев).
Larsa
Guest
0
18.03.2022 18:24:00
Но, пожалуйста, «@rextended», прекрати высказываться на людей, которые не знают об этих ограничениях! Скриптовый движок в таких вещах, как управление stdout/stderr, просто провален: например, он не умеет ловить сообщения об ошибках и не поддерживает коды ошибок. Реализация :put тоже провалилась, потому что она вовсе не делает то, чего от неё ждут люди.
stuartpbb
Guest
0
18.03.2022 22:29:00
Хорошо, но сейчас этот код использует переменные с глобальной областью видимости, а не локальные. Цель — применять локальную область, чтобы не сохранять состояние в глобальном окружении, если это не нужно, и держать локальные переменные внутри того блока кода, к которому они относятся. Ты также используешь :parse, чтобы обернуть fetch, и :delay — зачем это нужно/где это описано? По документации и примерам кода, которые я нашёл (), есть такой пример: { :local result [/tool fetch url=http://10.0.0.1/disable_ether2.php as-value output=user]; :if ($result->"status" = "finished") do={ :if ($result->"data" = "0") do={ /interface ethernet set ether2 disabled=yes; } else={ /interface ethernet set ether2 disabled=no; } } } Код, который я изначально использовал в качестве примера, работает, и $response устанавливается (у меня есть полностью рабочий скрипт, который так же работает примерно на 30 роутерах под управлением ROS v6 и v7), просто debug :put после этого не выводит никаких данных (в этом и был смысл этой темы).
Amm0
Guest
0
18.03.2022 23:03:00
Скрипты RouterOS точно ведут себя «последовательно, но непредсказуемо». Видимо, тут какой-то спорный баг. Но проблема, скорее, не в команде «:put», а в строке, которую она пытается вывести. Если при подстановке строки (иначе говоря, интерполяции) возникает ошибка, как иногда бывает с «:put "value=$val"», если $val — это массив, тогда строка может провалиться, и в ответ ничего не вернётся. Поскольку подстановка строки происходит до вызова «:put», когда «стек разворачивается» обратно к «:put», строка уже пустая. В общем, лучше всегда убеждаться, что подставляемые переменные — строки, пусть даже пустые, иначе они могут (а могут и не) «упасть» в зависимости от типа (число, массив, ip, ip6, ip-префикс и так далее), а когда строковая подстановка проваливается, возвращается пустая строка. Думаю, основная проблема в том, что ответ от /tool/fetch — это тип «массив», а интерполяция строк с массивами у RouterOS, мягко говоря, «капризная». Почему и когда — неясно, лучше не использовать массивы как переменные внутри строк.
Чтобы решить твою проблему, можно просто обернуть переменную в [:tostr $response], например так: :put "debug: response=$([:tostr $response])". Думаю, дополнительный «$([…])» вокруг переменной создаёт новый вызов в стеке, то есть ещё одну «зону обработки ошибок», так что если ошибка случится, стек «свернётся» только до этого вызова и пустую строку вернёт только он, а не весь скрипт. Теоретически ROS-скрипт должен сам пытаться привести к строке через :tostr, и, возможно, так и есть, но синтаксис $([…]) действует как «ловушка» для ошибок, по крайней мере, судя по моему опыту. :tostr важен тем, что он возвращает именно пустую строку, а не ошибку/nil/ничего.
В целом, по документации много пробелов, но главная беда — это «неряшливость» MikroTik с типами переменных. Например, какие-то команды CLI приводят типы автоматически, другие — нет, а некоторые преобразования возможны только с хитростями.
stuartpbb
Guest
0
19.03.2022 19:15:00
Amm0, спасибо. Твой ответ оказался самым полезным, и твоя оценка того, что RouterOS постоянно ведёт себя непредсказуемо, кажется вполне точной. Используя твоё предложение и изменив мой исходный пример кода на использование [:tostr], всё действительно работает:
Объяснение, что :put “заикается” при попытке вывести массив, хорошо подходит для этого постоянного непредсказуемого поведения OS. Я сделал более детальный тест, чтобы понять, что работает, а что нет:
Первый и второй :put ничего не выводят совсем, а третий и четвёртый — выводят. Что четвёртый выводит — для меня это непоследовательное поведение: RouterOS, кажется, неявно преобразует массив в строку, если выводится только он один, но не делает этого при конкатенации (и при этом не выдаёт ни ошибки, ни предупреждения). Мой опыт работы с другими языками показывает, что неявное преобразование нестроки в строку либо происходит как в пункте #4, либо преобразуется в что-то типа статической строки «{array}» в выводе. Полное отсутствие вывода — это (снова для меня) не последовательно и забирает лишнее время на попытки понять, что вообще происходит и отладить проблему.
В любом случае, думаю, я уже достаточно увлёкся в этой ветке — спасибо за полезные комментарии и разъяснения!
Amm0
Guest
0
19.03.2022 21:01:00
Моя мысль в том, что вина не в бедном операторе «:put». По сути, при подстановке переменных «лучшей практикой» было бы просто использовать «кастинг», в большинстве случаев это излишне. Но, как уже отмечалось, обработка ошибок в скрипте тоже ограничена, так что лучше вообще избегать появления ошибок. А вот с «.» и массивами все сложнее. Массив может хранить разные вещи (например, пары ключ-значение, список строк/чисел и т.д., функции или их смесь), и от того, что именно хранится, зависит, как сработает :put. Если у вас массив только из строк, он может работать примерно так, как вы ожидаете (хотя, думаю, всё равно не совсем).
Всё это работает, потому что внутри массива — обычные типы, например строки (или числа — то же самое). Но, как в вашем и в следующем примере, массивы могут хранить пары ключ-значение. И вот когда это происходит, подстановка строк уже не работает.
:global arrarr {a=1;b="txt"} :put "$arrarr" #a=1;b=txt :put "some text $arrarr" # ### как было сказано ранее в обсуждении — никакого вывода ###
Как работает оператор «точка .» с массивом, действительно описано в справке (например, он ведёт себя как функциональный оператор «set apply»), но почему в первом примере текст повторился — вопрос. Дальше, если у вас есть строка, а затем массив, скрипт может распознать «точечный оператор», если видит сначала строковый токен, а за ним массивный, как в «text$myarray», и поэтому получится тот же эффект. В общем, я буду дальше называть это последовательно — непоследовательно. В какой-то мере многие вещи имеют смысл — просто совсем не хватает нескольких примитивов, а типы получились асимметричными.
Amm0
Guest
0
19.03.2022 21:29:00
И еще кое-что. В документации и для справедливости к MT есть старый раздел «Советы и хитрости», на который ссылается текущий мануал по скриптам вот здесь: Там есть раздел с названием «Будьте осторожны при добавлении массива к строке», который, возможно, объясняет это лучше.