Информация
Услуги
  • Внедрение
  • Настройка
  • Поддержка
  • Ремонт
Контакты
Новинка
Распродажа
Новости
Доставка
Оплата
Загрузки
  • Прошивки
    • WinBox
    • RouterOS
    • Мобильные приложения MikroTik
    • Архив
  • RouterOS
  • Мобильные приложения MikroTik
  • Архив
Форум
Настройка
    info@mikrotik.moscow
    +7 495 320-55-52
    Заказать звонок
    Mikrotik.moscow
    Каталог
    • Акции
      Акции
    • Маршрутизаторы
      Маршрутизаторы
    • Коммутаторы
      Коммутаторы
    • Радиомосты и уличные точки доступа
      Радиомосты и уличные точки доступа
    • Wi-Fi для дома и офиса
      Wi-Fi для дома и офиса
    • LTE/5G
      LTE/5G
    • Powerline адаптеры
      Powerline адаптеры
    • IoT устройства
      IoT устройства
    • Оборудование 60 ГГц
      Оборудование 60 ГГц
    • Материнские платы RouterBOARD
      Материнские платы RouterBOARD
    • Корпуса
      Корпуса
    • Интерфейсы
      Интерфейсы
    • SFP/QSFP трансиверы
      SFP/QSFP трансиверы
    • Аксессуары
      Аксессуары
    • Антенны
      Антенны
    • Архив
      Архив
    Войти
    0 Сравнение
    0 Избранное
    0 Корзина
    Скачать WinBox Скачать Прошивки Форум > RouterOS Форум > SwOS Форум > Железо
    Mikrotik.moscow
    Каталог
    Войти
    0 Сравнение
    0 Избранное
    0 Корзина
    Mikrotik.moscow
    Телефоны
    +7 495 320-55-52
    Заказать звонок
    0
    0
    0
    Mikrotik.moscow
    • +7 495 320-55-52
      • Назад
      • Телефоны
      • +7 495 320-55-52
      • Заказать звонок
    • info@mikrotik.moscow
    • г. Москва, ул. Бакунинская, 84
    • Пн-Пт: 09-00 до 18-00
      Сб-Вс: выходной


    • Кабинет
    • 0 Сравнение
    • 0 Избранное
    • 0 Корзина
    Главная
    Форум
    Форум
    RouterOS
    Проблема с ":put" в скриптинге

    Проблема с ":put" в скриптинге

    Форумы: RouterOS, Аппаратное обеспечение, SwOS, Обратная связь, Объявления, Сторонние инструменты
    Поиск  Пользователи  Правила  Войти
    Страницы: 1
    RSS
    Проблема с ":put" в скриптинге, RouterOS
     
    Okietim
    Guest
    #1
    0
    01.01.2019 02:16:00
    Не получается использовать :put для вывода содержимого глобальной переменной внутри скрипта. В терминале cli всё работает нормально, и видно, что глобальная переменная меняется из скрипта, но при запуске скрипта в консоли никакого вывода нет. Использую версию 6.43.7 и последнюю Winbox. Искал решение на форуме и в гугле — без успеха. Буду признателен за советы.
     
     
     
    stuartpbb
    Guest
    #2
    0
    17.03.2022 02:35:00
    Могли бы вы обновить документацию, чтобы это отражалось? https://wiki.mikrotik.com/wiki/Manual:Scripting Я только что столкнулся с той же проблемой и был уверен, что это баг, пока не прочитал это.
     
     
     
    Jotne
    Guest
    #3
    0
    18.03.2022 13:24:00
    Когда у тебя есть скрипт, который запускается, скажем, ровно в 00:00 каждую ночь, где ты ожидаешь увидеть вывод :put? У тебя круглосуточно открыта терминальная сессия, которая ждёт этот вывод? Вот почему у нас есть :log, который отправляет вывод в лог или syslog. Данные также можно отправлять по email, ftp, http, мигать светодиодом +++ (гугли email, telegram +++++). Я использую :put только когда отлаживаю скрипт, чтобы в терминале увидеть, что там происходит во время теста.
     
     
     
    stuartpbb
    Guest
    #4
    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";
       }

       :local response [/tool fetch http-method=post http-data=$data output=user url="https://httpdump.io/eyxhj" as-value];

       :put "debug: response=$response";
    }

    Я проверял это на RouterOS v6 и v7: оба выведут первую команду :put, но вторую нет. Моя версия — внутренний блок кода (используемый, чтобы переменная :local foo была видна только внутри него) перенаправляет вывод так, что :put после fetch просто не появляется в консоли. В документации я ничего не нашёл, что объясняло бы такое поведение, поэтому и попросил обновить документацию, чтобы объяснить случаи, когда :put ведёт себя не так, как логично ожидать (и как работают print в других языках сценариев).
     
     
     
    Larsa
    Guest
    #5
    0
    18.03.2022 18:24:00
    Но, пожалуйста, «@rextended», прекрати высказываться на людей, которые не знают об этих ограничениях! Скриптовый движок в таких вещах, как управление stdout/stderr, просто провален: например, он не умеет ловить сообщения об ошибках и не поддерживает коды ошибок. Реализация :put тоже провалилась, потому что она вовсе не делает то, чего от неё ждут люди.
     
     
     
    stuartpbb
    Guest
    #6
    0
    18.03.2022 22:29:00
    Хорошо, но сейчас этот код использует переменные с глобальной областью видимости, а не локальные. Цель — применять локальную область, чтобы не сохранять состояние в глобальном окружении, если это не нужно, и держать локальные переменные внутри того блока кода, к которому они относятся. Ты также используешь :parse, чтобы обернуть fetch, и :delay — зачем это нужно/где это описано? По документации и примерам кода, которые я нашёл (https://wiki.mikrotik.com/wiki/Manual:Tools/Fetch), есть такой пример:  
    {  
       :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
    #7
    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
    #8
    0
    19.03.2022 19:15:00
    Amm0, спасибо. Твой ответ оказался самым полезным, и твоя оценка того, что RouterOS постоянно ведёт себя непредсказуемо, кажется вполне точной. Используя твоё предложение и изменив мой исходный пример кода на использование [:tostr], всё действительно работает:

    {
       :local data "this is a test";

       {
           :local test [:toarray ""];
           :set ($test->"foo") "bar";
           :set ($test->"bar") "baz";

           :put "debug #1: test=$test";
           :put ("debug #2: test(concat)=" . $test);
           :put "debug #3: test(tostr)=$[:tostr $test]";
           :put "debug #4: test="; :put $test;
       }

       :local foo [/system routerboard get board-name];
       :set data ($data . "\n" . $foo);
       :put "debug: added to data: $foo";
    }

    :local response [/tool fetch http-method=post http-data=$data output=user url="https://httpdump.io/eyxhj" as-value];

    :put ("debug: typeof response=" . [:typeof $response]);
    :put ("debug: response=" . [:tostr $response]);
    }

    Объяснение, что :put “заикается” при попытке вывести массив, хорошо подходит для этого постоянного непредсказуемого поведения OS. Я сделал более детальный тест, чтобы понять, что работает, а что нет:

    {
       :local test [:toarray ""];
       :set ($test->"foo") "bar";
       :set ($test->"bar") "baz";

       :put "debug #1: test=$test";
       :put ("debug #2: test(concat)=" . $test);
       :put "debug #3: test(tostr)=$[:tostr $test]";
       :put "debug #4: test="; :put $test;
    }

    Первый и второй :put ничего не выводят совсем, а третий и четвёртый — выводят. Что четвёртый выводит — для меня это непоследовательное поведение: RouterOS, кажется, неявно преобразует массив в строку, если выводится только он один, но не делает этого при конкатенации (и при этом не выдаёт ни ошибки, ни предупреждения). Мой опыт работы с другими языками показывает, что неявное преобразование нестроки в строку либо происходит как в пункте #4, либо преобразуется в что-то типа статической строки «{array}» в выводе. Полное отсутствие вывода — это (снова для меня) не последовательно и забирает лишнее время на попытки понять, что вообще происходит и отладить проблему.

    В любом случае, думаю, я уже достаточно увлёкся в этой ветке — спасибо за полезные комментарии и разъяснения!
     
     
     
    Amm0
    Guest
    #9
    0
    19.03.2022 21:01:00
    Моя мысль в том, что вина не в бедном операторе «:put». По сути, при подстановке переменных «лучшей практикой» было бы просто использовать «кастинг», в большинстве случаев это излишне. Но, как уже отмечалось, обработка ошибок в скрипте тоже ограничена, так что лучше вообще избегать появления ошибок. А вот с «.» и массивами все сложнее. Массив может хранить разные вещи (например, пары ключ-значение, список строк/чисел и т.д., функции или их смесь), и от того, что именно хранится, зависит, как сработает :put. Если у вас массив только из строк, он может работать примерно так, как вы ожидаете (хотя, думаю, всё равно не совсем).

    :global strarr {"abc"; "def"}  
    :put [len $strarr]
    # 2  
    :put [typeof $strarr]
    array  
    :put "strarr=$strarr"  
    #strarr=abc;strarr=def  
    :global strstrarr "strarr=$strarr"  
    :put [len $strstrarr]
    #2  
    :put [typeof $strstrarr]
    #array  
    :put $strstrarr  
    #strarr=abc;strarr=def  
    :put ($strstrarr->0)  
    #strarr=abc  
    :put "onemorelevel=$strstrarr"  
    #onemorelevel=strarr=abc;onemorelevel=strarr=def  

    Всё это работает, потому что внутри массива — обычные типы, например строки (или числа — то же самое). Но, как в вашем и в следующем примере, массивы могут хранить пары ключ-значение. И вот когда это происходит, подстановка строк уже не работает.

    :global arrarr {a=1;b="txt"}  
    :put "$arrarr"  
    #a=1;b=txt  
    :put "some text $arrarr"  
    # ### как было сказано ранее в обсуждении — никакого вывода ###  

    Как работает оператор «точка .» с массивом, действительно описано в справке (например, он ведёт себя как функциональный оператор «set apply»), но почему в первом примере текст повторился — вопрос. Дальше, если у вас есть строка, а затем массив, скрипт может распознать «точечный оператор», если видит сначала строковый токен, а за ним массивный, как в «text$myarray», и поэтому получится тот же эффект. В общем, я буду дальше называть это последовательно — непоследовательно. В какой-то мере многие вещи имеют смысл — просто совсем не хватает нескольких примитивов, а типы получились асимметричными.
     
     
     
    Amm0
    Guest
    #10
    0
    19.03.2022 21:29:00
    И еще кое-что. В документации и для справедливости к MT есть старый раздел «Советы и хитрости», на который ссылается текущий мануал по скриптам вот здесь: https://wiki.mikrotik.com/wiki/Manual:Scripting_Tips_and_Tricks Там есть раздел с названием «Будьте осторожны при добавлении массива к строке», который, возможно, объясняет это лучше.
     
     
     
    Страницы: 1
    Читают тему
    +7 495 320-55-52
    info@mikrotik.moscow
    Электрозаводская, Бауманская
    Москва, ул. Бакунинская, 84с21
    Конфиденциальность Оферта
    © 2026 «Mikrotik.Moscow»
    Главная Каталог 0 Корзина 0 Избранные Кабинет 0 Сравнение Акции Контакты Услуги Бренды Отзывы Компания Лицензии Документы Реквизиты Поиск Блог Обзоры