LINUX.ORG.RU

Не могу разобраться в циклах

 , , ,


1

2

Есть программка которая циклично выводит обновляемые данные.

~$./prog
{
  "something Something": {
     "strings": [
        12.454398734,
        -32.39841032,
        88.382397873
      ]
   }
}
{
  "something Something": {
     "strings": [
        -34.12312344,
        555.12343442,
        -22.42342344
      ]
   }
}
^C
~$

Как во время обновления данных, сравнивать выводимые перед точкой значения с заданными числами например больше чем 100 и меньше чем -100 ?

Если бы команда prog выводила значение и завершалась, я бы видел это так:

check='sh prog'
for var in $check
do
if [ если одно из чисел перед точкой больше чем 100 или меньше чем -100 ]
then         
echo "Alert"
fi
done
Но переменная check ждёт вывода prog, но prog не может вернуться потому что зациклен. Так же мне не понятно, как сравнить числа с двойный набором условий?

Ответ на: комментарий от WildUser

prog | sed выводит в реальном времени, а с awk нет

и

Всё таки это awk тормозит.

Весьма странно. awk не должна тормозить в такой ситуации даже на слабом компе, а буфер в моём однострочнике точно ни при чём.

Я думаю всё таки поможет read, который вы описали выше.

Попробуйте вместо awk подставить такой bash скрипт:

#!/bin/bash

while true;
 do
   read var;
   if [ "$(echo $var | grep -F '.')" ];
     then
       vari="$(echo -n $var | sed 's/\..*//')";
       varf="$(echo -n $var | sed 's/.*\.//')";
   else
     if [ -n "$var" ];
       then
         vari=$var;
         varf=0;
     else
         # Если вместо continue поставить break,
         # то при встрече пустой строки скрипт прервётся:
         continue;
     fi;
   fi;
   if [ -z "$vari" ];
     then
       vari=0;
   fi;
   echo -n "$var: ";
   if [ "$vari" -gt -100 -a "$vari" -lt 100 ];
     then
       echo Ok.;
   else
     if [ "$vari" -lt -100 -o "$vari" -gt 100 -o "$varf" -gt 0 ];
       then
         echo Alert.;
     else
         echo Ok.;
     fi;
   fi;
 done

Этот скрипт учитывает цифры и после точки.

Можно ещё попробовать вместо awk, скрипта и sed’а такую c-программку:

#include <stdio.h>
#include <stdlib.h>

int main()
{
  double n;
  char *ptr, *endptr, buf[4096];
  while(!feof(stdin))
  {
    if((endptr=fgets(buf, sizeof(buf), stdin))!=NULL)
    {
      do
      {
        ptr=endptr;
        n=strtod(ptr, &endptr);
        if(endptr && endptr!=ptr)
         printf("%f: %s.\n", n, n<-100.0 || n>100.0 ? "Alert" : "Ok");
      } while(*endptr && endptr!=ptr);
    }
  }
  return 0;
}

Компилируете её командой gcc -o alert100 -Wall -O3 -g0 alert100.c, где alert100.c — название исходника, а alert100 — название выходной исполняемой программы, вместо них можно придумать свои названия. И затем запускаете командой prog | ./alert100. Программа умеет читать по нескольку чисел из строки, поэтому sed ей не нужен. Массив buf для входной строки я установил в 4096. Если строки могут быть больше, то нужно увеличить это число. Если же строки абсолютно всегда намного меньше, то можно уменьшить, но так, чтоб помимо строки в buf помещалось ещё по меньшей мере 2 символа: символ новой строки и 0. В выводе программы есть одно отличие: числа с большим числом 0 после точки округляются при выводе, но не при сравнениях, из-за чего иногда можно увидеть что-то вроде:

-100.000000: Alert.
100.000000: Alert.
-100.000000: Ok.
100.000000: Ok.

Чтоб Alert и Ok соответствовали выводимому числу в таких случаях, достаточно увеличить точность вывода с помощью флагов форматирования в функции printf.

Обязательно отпишитесь, помогли или не помогли эти варианты. Потому что самому стало интересно, что у вас там с awk происходит.

Мне нужно что бы alert запускался одноразово и сценарий закрывался.

Этого в исходной формулировке задачи не было. Для этого в bash и awk есть команда exit, а в языке си — оператор return.

aureliano15 ★★
()
Последнее исправление: aureliano15 (всего исправлений: 1)
Ответ на: комментарий от aureliano15

Спасибо, буду ковырять) Возможно отсутствие рута в смартфоне делает некие ограничения или сам termux неполноценный. На C интересно будет проверить но на практике моя задумка должна реализовываться тривиальными консольными инструментами. Отпишусь обязательно, ещё раз спасибо

WildUser
() автор топика
Ответ на: комментарий от aureliano15
~ $ ./prog | ./aureliano15.sh
{: ./aureliano15.sh: line 26: [: {: integer expression expected
./aureliano15.sh: line 30: [: {: integer expression expected
Ok.
"something Something": {: ./aureliano15.sh: line 26: [: "something Something": {: integer expression expected
./aureliano15.sh: line 30: [: "something Something": {: integer expression expected
Ok.
"values": [: ./aureliano15.sh: line 26: [: "values": [: integer expression expected
./aureliano15.sh: line 30: [: "values": [: integer expression expected
Ok.
-95.68634033203125,: Ok.
4.974365234375,: Ok.
2.35137939453125: Ok.
]: ./aureliano15.sh: line 26: [: ]: integer expression expected
./aureliano15.sh: line 30: [: ]: integer expression expected
Ok.
}: ./aureliano15.sh: line 26: [: }: integer expression expected
./aureliano15.sh: line 30: [: }: integer expression expected
Ok.
}: ./aureliano15.sh: line 26: [: }: integer expression expected
./aureliano15.sh: line 30: [: }: integer expression expected
Ok.
^C
~ $

Если поступают значения больше или меньше 100 проскакивает и Alert.

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

У вас есть смартфон?)

WildUser
() автор топика
Ответ на: комментарий от WildUser

Кажется, дело всё-таки в буферизации. Попробовал сэмулировать ./prog скриптом, генерирующим случайные числа:

#!/bin/bash

while true
  do
    n=$(expr $RANDOM % 10000 + 1);
    while [ $n -gt 0 ]
     do
       echo -n "`expr $RANDOM % 130`.$RANDOM";
       let n-=1;
       if [ $n -ne 0 ]
         then
           echo -n " ";
       fi
     done
     echo;
  done

В выражении $RANDOM % 10000 + 1 определяется максимальное количество чисел в 1 выходной строке (в данном случае 10000).

И да, и sed, и awk подтормаживают даже когда в стоке ровно 1 число ($RANDOM % 1), а уж когда их может быть до 10000, — ожидание ввода может длиться до 10 секунд, если не больше. Улучшает ситуацию stdbuf -oL или stdbuf -o0 для sed, т. е. буферизует именно он. Команда

./init_rand.sh | stdbuf -oL sed 's/[\t ]\+/\n/g' | awk '{printf $1": "; if($1<-100 || $1>100) print "alert"; else print "Ok";}'

при длине строки до 100 чисел вообще молотит, не останавливаясь, а при длине до 10000 чисел — приостанавливается, но ненадолго. Интересно, что если сохранить вывод init_rand.sh в текстовый файл, а потом cat’ом вывести его, то никакой stdbuf не нужен, — всё летает. Однако модификация буферизации самого init_rand.sh никак не влияет на задержки при выводе, — изменять буферизацию надо именно для sed. В общем, понятно, что ничего непонятно, однако методом научного тыка установлено, что по крайней мере у меня sed, похоже, буферизует слишком большие порции, но делает это только тогда, когда получает на вход данные от скрипта, а не из cat. @i-rinat, ты вроде разбираешься в таких непонятных случаях. Может есть идеи, отчего такое может быть?

./aureliano15.sh: line 26: [: {: integer expression expected

Я проверил этот скрипт на своём формате, который приводил здесь. Скорее всего, ваши данные выводятся в несколько ином формате. Выложите на какой-нибудь https://pastebin.com/ вывод своей prog точно в том виде, в каком она его выдаёт, со всеми пробелами и прочими символами.

сравнивать нужно числа перед точкой.

Тогда из скрипта нужно просто убрать varf и все проверки, связанные с ним. А vari и var оставить.

У вас есть смартфон?)

Есть. Но я им пользуюсь только как телефоном и навигатором. Поэтому если надо сделать на нём что-то менее тривиальное, мне могут потребоваться подробные инструкции для нуба. Однако, думаю, дело скорее всего не в девайсе и не в ОС, а в формате вывода prog.

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

https://pastebin.com/y35rtKFE

С stdbuf тоже чёт непонятное, выводит прежде чем условия будут достигнуты.

Есть. Но я им пользуюсь только как телефоном и навигатором. Поэтому если надо сделать на нём что-то менее тривиальное, мне могут потребоваться подробные инструкции для нуба. Однако, думаю, дело скорее всего не в девайсе и не в ОС, а в формате вывода prog.

Дело не в девайсе верно, а возможно в особенностях вывода этой программы. Если не сложно скачайте мизерный эмулятор из плеймаркета, называется termux и модуль termux api когда откроете интегрируйте софт для этой api командной

pkg install termux-api

Далее всё очень просто: смотрим список сенсоров

termux-sensor -l

выбираете имя Магнетометра и:

termux-sensor -s name_sensor

по умолчанию выводит раз в секунду (-d 1000), вывести 10 раз -n 10

WildUser
() автор топика
Ответ на: комментарий от WildUser

через вайфай можно подключится к самому termux, для этого нужно поставить в него отдельно pkg install openssh. запустить сразу демон sshd. адрес в сети можно посмореть тем же ip a, а порт на котором работает ssh по умолчанию 8022

WildUser
() автор топика
Ответ на: комментарий от WildUser

https://pastebin.com/y35rtKFE

{
  "BN34582 Magnetometer": {
    "values": [
      -7.79571533203125,
      -109.918212890625,
      2.7557373046875
    ]
  }
}

Понятно, что на такой вывод ни скрипт, ни программа на си не рассчитаны. Я понял, что речь идёт только о числах. Вам надо было учитывать специфику ЛОРа, где обычно верхний пост не читай, сразу отвечай, и указать на это в ответах. Для такого формата вывода должен подойти следующий скрипт:

#!/bin/bash

while read str;
  do
    str="$(echo -n "$str" | sed 's/^\.//')";
    var="$(echo -n $str | sed 's/^[ \t]\+//;s/,$//')";
    echo -n "$str"
    if [ -z "$(echo -n $var | tr -d '+-.0123456789')" ]
      then
        vari="$(echo -n $var | sed 's/\..*//')"
        if [ -z "$vari" ]
          then vari=0;
        fi
        if [ $vari -gt 100 -o $vari -lt -100 ]
          then
            echo -n "                    Alert";
            # Если в этом случае надо выйти --- раскомментировать:
            # exit;
        fi
    fi
    echo; # Просто добавляем newline.
  done

Запускается он тоже после фильтра sed таким способом: ./prog | sed 's/\(.*\)/\.\1/' | ./alert100-2.sh. Скрипт выводит без изменений полученные на вход данные с пометкой «Alert» в нужных местах. Вот пример вывода на ваших данных:

{
  "BN34582 Magnetometer": {
    "values": [
      -7.79571533203125,
      -109.918212890625,                    Alert
      2.7557373046875
    ]
  }
}

На самом деле sed нужен только для добавления точки в начале каждой строки, которая потом удаляется скриптом, но позволяет при чтении с помощью read сохранить отступы. Если сохранять отступы при выводе не нужно, то можно убрать этот sed, а в самом скрипте удалить первую строчку str="$(echo -n "$str" | sed 's/^\.//')";, а во второй строчке удалить из выражения sed цепочку s/^[ \t]\+//;, хотя это уже необязательно. Скрипт не учитывает дробную часть, просто отбрасывая её, поэтому 100.9999 и -100.9999 попадут в диапазон допустимых значений (алерта не будет). Кроме того, скрипт исходит из того, что в 1 строке может быть не более 1 числа. В случае 2 и более чисел в одной строке он будет работать неправильно. Ну и есть ещё 1 нюанс, который скорее всего не имеет значения, но в теории можно создать строку, которая будет неправильно идентифицирована как число. Дело в том, что после удаления ведущих пробелов и табуляций и завершающих запятых, проверка на то, что строка является числом, осуществляется просто проверкой допустимости всех символов для числа, а это помимо цифр ещё "+, «-» и «.». Т. о. строка вида «12345+.-67890» будет обрабатываться, как допустимое число, и на ней вылезет ошибка. Я не думаю, что такие строки практически возможны, поэтому не пытался обработать эту ситуацию. Но если возможны, то обработка должна быть более сложной.

С stdbuf тоже чёт непонятное, выводит прежде чем условия будут достигнуты.

Не понял смысла вопроса или ремарки.

скачайте мизерный эмулятор из плеймаркета, называется termux и модуль termux api [skip] Далее всё очень просто: смотрим список сенсоров termux-sensor -l

Установил, поставил termux-api, и всё застопорилось на команде termux-sensor -l. Видимо, определяющихся сенсоров у меня нет.

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Установил, поставил termux-api, и всё застопорилось на команде termux-sensor -l. Видимо, определяющихся сенсоров у меня нет.

Вы установили termux-api в самой оболочке? pkg install termux-api Нужно ещё дать все разрешения termux и termux api в настройках андроида. Если у api нет доступа к геолокации то и оболочка не получит доступ к акселерометру и магнитометру.

Ваш код сейчас проверю, отпишу позже. Спасибо

WildUser
() автор топика
Ответ на: комментарий от aureliano15

Работает как часы без sed. НО не смотря на указание частоты обновления сенсора, данные выводит не больше чем 3-4 раза в секунду, соответственно всё что попадает позже накапливается в буфер и запустит Алерт только когда дойдёт очередь на вывод) Вобщем-то с while интереснее выглядит и понятнее.

WildUser
() автор топика
Ответ на: комментарий от WildUser

Можно попробовать поиграться с stdbuf, подставляя его перед prog и alert100-2.sh с опцией -oL (построчная буферизация) или даже -o0 («-o ноль», вообще без буферизации). Не уверен, что поможет, но вдруг…

не больше чем 3-4 раза в секунду

Хотя, с другой стороны, скорость обновления 1/4 — 1/3 секунды, имхо, вполне достаточная для визуального мониторинга, т. к. при более высокой скорости можно просто не успеть увидеть, что там проскочило, и всё равно придётся или писать логи, просматривая их задним числом, или использовать less, листая вывод, или просто приостанавливать этот вывод сочетанием клавиш ctrl+s, а потом возобновлять ctrl+q. Т. е. получится, что сначала мы пытаемся ускорить вывод, а потом специально замедляем его. Человеческие глаза и мозги всё равно не разгонишь, как процессор. :-)

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Дело в том что скачок показателей датчиков может происходить меньше чем 1/50 секунды, соответственно скорость обновления в 1/3 секунды просто не увидит этих изминений. Программа должна запускать внешний сценарий на случай обнаружения критических значений, смотреть там ничего не надо) С stdbuf поиграюсь, но думаю так быстро как нужно отсюда не выжить простым способом.

Termux поставили?) Вобще очень интересная вещь для смартфона, можно развернуть свой сервер! Слышали бы меня наши предки «сервер!» портативный, переносимый и довольно шустрый, а ещё и со своими датчиками ориентации в пространстве камерой и многим другим)

WildUser
() автор топика
Ответ на: комментарий от WildUser

скорость обновления в 1/3 секунды просто не увидит этих изминений. Программа должна запускать внешний сценарий на случай обнаружения критических значений, смотреть там ничего не надо

Тогда это задача реального времени, и я бы:

  1. Не выводил бы никакую информацию на экран, т. к. вывод на экран по определению всё замедляет, а сразу же при обнаружении критического значения запускал подпрограмму с нужным действием (отключением сенсора или не знаю что ещё).

  2. Писал бы такую программу на компилируемом в машинный код языке, например на си, а не на bash или других интерпретируемых языках или языках, интерпретирующих байт-код (что почти то же самое).

  3. Поднял бы приоритет этой задачи. Но сама программа должна быть написана очень аккуратно и как можно быстрее засыпать, когда ей нечего делать, иначе при повышении приоритета она сожрёт почти всё процессорное время, и остальные задачи могут начать дико тормозить.

Все эти меры ни в коем случае не гарантируют реакцию в реальном времени. Для гарантий нужна либо ОСРВ, либо, в крайнем случае, модуль должен работать в режиме ядра. Однако сильно повысит вероятность своевременного мгновенного реагирования.

Termux поставили?

Поставить-то поставил, но как разрешить ему доступ к геолокации, — так и не нашёл. В разрешениях прописаны возможность просмотра сетевых подключений, доступ к Интернету и ещё 4 разрешения, но возможности что-то добавить к ним там нет. В меню Геолокация имеется список программ, которым разрешено ею пользоваться, но termux’а там нет, как и возможности добавления его туда.

Вобще очень интересная вещь для смартфона, можно развернуть свой сервер!

Согласен. Правда, мне пока непонятно, зачем оно на телефоне, но терминал в телефоне — действительно прикольно. Пока удалять не планирую. Может, и найду какое применение.

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

За вывод на экарн отвечает echo -n "$str"? Скорость реакции конечно не супер но для моих задач вполне достаточно, главное работает)

Поставить-то поставил, но как разрешить ему доступ к геолокации, — так и не нашёл. В разрешениях прописаны возможность просмотра сетевых подключений, доступ к Интернету и ещё 4 разрешения, но возможности что-то добавить к ним там нет. В меню Геолокация имеется список программ, которым разрешено ею пользоваться, но termux’а там нет, как и возможности добавления его туда.

Да в андройде эти функции могут быть спрятаны в разных местах и доступ к оборудованию нужно давать именно termux-api, сам termux по умолчанию и не требует таких привилегий кроме доступа к постоянной памяти и в списке разрешений его быть не может.

Согласен. Правда, мне пока непонятно, зачем оно на телефоне, но терминал в телефоне — действительно прикольно. Пока удалять не планирую. Может, и найду какое применение.

Ну как же как не вам понимать зачем это в телефоне?) Век высоких технологий, портативность и автономность, высокая энергоэффективность. x86 скоро полностью поселятся в датацентрах, а ARM займут место на рабочих столах обычных людей и разработчиков.

Смартфон имеет всё для непрерывной работы включая неплохой GSM модуль который работает в 2021 очень даже круто. Маленькая штучка в 150грамм может полностью заменить ноутбук, а учитывая что давным давно есть всякие VNC для связи с десктопом, нужда в грамоздких и прожорливых x86 отпадает.

Ну конечно же забыл упомнить MacBook M1 )) Вещь конечно бомба, свой проц всё своё.

А termux имеет довольно подробную документацию и большое сообщество разработчиков и пользователей. Главное его преимущество это полноценная среда без root доступа. Банальный sshd в свою трубку это просто musthave любого любителя командной строки)

WildUser
() автор топика
Ответ на: комментарий от WildUser

За вывод на экарн отвечает echo -n "$str"?

За вывод входной строки без перевода строки (за счёт опции -n) — он самый. А за вывод алерта — echo -n " Alert";. Ну и в конце ещё один echo; без аргументов и без опции -n для перевода строки.

Скорость реакции конечно не супер но для моих задач вполне достаточно, главное работает)

В любом случае, нет смысла всё это выводить на стандартный вывод, если его никто не смотрит. В крайнем случае — только сенсор, который сбойнул, номер или название зашкалившего параметра и его значение, например "BN34582 Magnetometer":2:-109.918212890625 для приведённого здесь примера, где 2 — порядковый номер параметра. И выводить в лог, а не в стандартный вывод. Хотя стандартный вывод всегда можно перенаправить в лог.

А вот что необходимо добавить для программной реакции на разные события, — ту самую связку сенсор:параметр:значение, т. к. сам по себе алерт ничего не говорит о том, что сбойнуло и насколько сильно зашкалило.

x86 скоро полностью поселятся в датацентрах, а ARM займут место на рабочих столах обычных людей и разработчиков.

Даже когда выполнялся закон Мура (а времена эти прошли уже больше 10 лет назад), софт жирел намного быстрее железа. Датацентры для тех, кто готов полностью зависеть от дяди и провайдера, а заодно готов поделиться с этим дядей из датацентра всеми своими секретами.

Смартфон имеет всё для непрерывной работы включая неплохой GSM модуль

Там, где есть кабельный или ещё какой интернет, gsm не нужен. А там, где его нет, можно подключить модем или тот же смартфон в качестве такового. Смартфон нужен только для того, чтобы его таскать. На стационарном рабочем месте он не нужен.

а учитывая что давным давно есть всякие VNC для связи с десктопом, нужда в грамоздких и прожорливых x86 отпадает.

Для комфортной работы (да и для развлечений) помимо системного блока нужна ещё нормальная клавиатура, монитор и мышь. В результате мы в любом случае получаем формат не меньше ноутбука или моноблока.

Банальный sshd в свою трубку это просто musthave любого любителя командной строки)

Согласен, что вещь прикольная. Но всё-таки полноценный сервер, на мой взгляд, не должен зависеть от уровня заряда батареи и должен стоять в одном месте и работать как правило 24/7. Плюс желателен нормальный hdd хотя бы для логов. Ну и в зависимости от выполняемых задач, железо может быть и слабым, как смартфон, и жирным.

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Может есть идеи, отчего такое может быть?

Идей нет.

И честно говоря, оно того не стоит. Тут уже проще брать Python или Perl и писать обработку на нём. Парсить JSON регулярками — так себе развлечение.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Тут уже проще брать Python или Perl и писать обработку на нём.

Согласен. Задача, как я её понял, на баше в принципе решаема, но это не самый подходящий инструмент для неё.

aureliano15 ★★
()

Хрень мелкая. bash вам в профиль. Остальной фикней-ниже не верте! там алчные пацаны. Просто читайте.

Bootmen ☆☆☆
()
Ответ на: комментарий от Bootmen

расшифруйте пожалуйста что вы несёте)

WildUser
() автор топика
Ответ на: комментарий от WildUser

Увидел в вашем профиле, что вы заходили после моего ответа. Поэтому удалил его, предполагая, что вы успели прочитать. Если нет, и кнопка «Показать удаленные комментарии» вам недоступна, — напишите, повторю.

aureliano15 ★★
()
15 ноября 2021 г.
Ответ на: комментарий от futurama

Здравствуйте. Очень классный код. Но мне выводит значения только когда значения начинают сильно меняться, а не когда они привышают какие-то значения. Как это работает?

WildUser
() автор топика
Ответ на: комментарий от WildUser

Как во время обновления данных, сравнивать выводимые перед точкой значения с заданными числами например больше чем 100 и меньше чем -100 ?

Мой пример реагирует на числа > 100 и < -100

futurama ★★★★★
()

Не могу разобраться в циклах

goto + счетчик вместо них используйте …

anonymous
()
Ответ на: комментарий от ashot

Может вы подскажите, как же всё таки сделать рабочий вариант?) Что-то клеится уже почти год.

WildUser
() автор топика
Ответ на: комментарий от futurama

Теперь понял как. Спасибо! Как заставить выполнять действие при достижении реакции?

WildUser
() автор топика
Ответ на: комментарий от WildUser
./your_prog | grep -Eo -- '-?[0-9][0-9][0-9]\.[0-9]*,?$' | xargs -L1 -I{} /path/to/your/action.sh {}

На каждое найденное число >100.0 или <-100.0 будет вызываться

/path/to/your/action.sh <здесь_найденное_число>

futurama ★★★★★
()
Последнее исправление: futurama (всего исправлений: 1)
Ответ на: комментарий от futurama

Благодарю, работает. Допустим такой вариант, если нужно однократно запускать action.sh ?

./your_prog | grep -Eo -- '-?[0-9][0-9][0-9]\.[0-9]*,?$' | read -n1; ./action.sh

WildUser
() автор топика
Последнее исправление: WildUser (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.