LINUX.ORG.RU

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

 , , ,


0

1

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

~$./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 не может вернуться потому что зациклен. Так же мне не понятно, как сравнить числа с двойный набором условий?

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

Я не понимаю что такое конвейер. Код программы недоступен.

Двойной набор имеею ввиду что сравнивать надо не только «больше чем 100» но и «меньше чем -100», поправьте если я неправильно выразился

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

Я не понимаю что такое конвейер. Код программы недоступен.

Это передача вывода одной программы/скрипта на вход другой через символ трубопровода |: prog | prog2

А prog2 на баше мог бы читать в бесконечном цикле входные данные командой read в переменную $var и дальше точно так же обрабатывать.

Двойной набор имеею ввиду что сравнивать надо не только «больше чем 100» но и «меньше чем -100»

На bash: if [ "$var" -lt -100 -o "$var" -gt 100 ].

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

Идея понятна, но в каком виде read будет хранить данные и где? Память не закончится?) Не будет ли он просто накапливать бесконечный вывод? Как он поймёт длинну вывода за один цикл?

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

в каком виде read будет хранить данные и где?

read var1 var2 ... varN прочитает слова в переменные $var1, $var2, …, $varN. Если число слов в строке заранее известно, то можно подставить в read нужное число переменных. Иначе, если вывод исходной программы построчный и в строке переменное число слов, которые надо сравнивать, то передавай read одну переменную read var, и вся строка запишется в неё. После чего анализируешь в подцикле for i in $var.

Кроме того, возможно для твоей задачи будет проще использовать скрипт на awk, а не на bash. Посмотри возможности этой программы и синтаксис её языка.

Память не закончится?) Не будет ли он просто накапливать бесконечный вывод?

Нет. Если ты поставишь read в цикле, то она в каждой новой итерации будет перезаписывать переменную. Команда awk тоже будет обрабатывать ввод построчно.

Как он поймёт длинну вывода за один цикл?

Он просто будет читать по словам, разделённым пробелами. Если слов будет меньше, чем переменных, то в последние переменные запишутся пустые строки. Если больше, то в самую последнюю запишется остаток строки. Если read передать одну переменную, то в неё запишется вся строка. После символа новой строки чтение заканчивается.

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

Спасибо запускается без ошибок но ничего не происходит) (значения 100 и -100 поступают в обработчик) как посмотреть корректность выводимых строк jq? Мне кажется в этом проблема. Дикий код, ничего не понимаю

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

Оно немного кривенько, так как из float делает int простым отрезанием после точки. (test понимает только int) Т.е. из 100.1 получается 100.

Замени -lt (<) на -le (<=) и -gt (>) соответсвенно на -ge (>=).

Или если надо в другую сторону, то поменяй 100 на 101, а -100 на -101.

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

Альтернатива с awk, наверное будет более понятно:

./prog | jq '."something Something"."strings"[]' | awk '{ if ($1 > 100 || $1 < -100) print "yes", $1 }'
beastie ★★★★★ ()
Последнее исправление: beastie (всего исправлений: 2)
Ответ на: комментарий от beastie

Я не пойму что делает jq? Он исключает строки something, Something и strings? Потом отдаёт awk только числа? Но в них ведь присутствуют ещё запятые. У меня всё крашится либо никакой реакции.

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

jq парсит json и в данном случае выдаёт только цифры. С твоим же примером:

cat <<EOF |
{
  "something Something": {
     "strings": [
        12.454398734,
        -32.39841032,
        88.382397873
      ]
   }
}
{
  "something Something": {
     "strings": [
        -34.12312344,
        555.12343442,
        -22.42342344
      ]
   }
}
EOF
jq '."something Something"."strings"[]'

выдаст:

12.454398734
-32.39841032
88.382397873
-34.12312344
555.12343442
-22.42342344

ну, а далее awk читает этот выхлоп построчно и даст в данном примере:

yes 555.12343442
beastie ★★★★★ ()
Ответ на: комментарий от roof
~$termux-sensor -s sensor_name
{
 "sensor_name Accelerometer": {
  "values": [
    0.13231434
    8.123123123
    -5.31123123
    ]
  }
}
^C
~$

Это один цикл. Команду можно запустить с ключом -n 1 и она выведет только один цикл, но время выполнения команды оставляет желать лучшего.. Парсить данные нужно с большой скоростью, например 100раз в секунду с помощью ключа -d 10 но в этом случае выполнение должно быть зациклено что бы не перезапускать команду.

1. Незнаю как проверить 2. правильно, проверял каждый символ.

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

Всё, работает в цикле теперь. Нужно было запустить «cleanup». Если этого не сделать то сенсор просто не отвечает.. termux-sensor -c решил проблему.

Теперь данные выводит как надо в три строки за цикл, только числа, но с точками. Сейчас попробую все методы ещё раз и отпишу что вышло.

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

Извиняюсь, всё таки работает. Только вывод приходится ждать от 1-5 секунд. Я просто завершал работу скрипта так как сразу не видел результат.. Это awk так медленно считает?

Теперь этот вывод нужно направить в цикл while или until? Я весь день вчера читал так и не понял в чём их разница..

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

Вы прям Иесус во плоти. Всё работает спасибо) Если бтцкош оставишь, позже отправлю благодарность. Один вопрос: почему awk так медленно считает? От обновления значений до вывода может пройти до 10 секунд

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

Правильный ход моих мыслей?

Нет. Одного awk в данном случае достаточно. Или одного bash — это уже дело вкуса. Но awk короче. Про jq и json ничего не скажу, т. к. не пользовался.

почему awk так медленно считает? От обновления значений до вывода может пройти до 10 секунд

Это может быть и не awk, а jq. Временно убери awk, оставив только jq, если время заметно не сократится — тогда точно оно, иначе — нет. Если оно, то попробуй обойтись без него. Насколько я понял, оно используется, чтобы разбить твои слова в цикле на строки и, возможно, для дополнительного форматирования. Но всё это можно сделать и на bash.

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

Так красивее и короче. Здорово!

А что можно с задержкой сделать? alert запускается через 5-10 секунд, это всё таки может быть awk? 30 строк в секунду не такая уже сложная математическая задача вроде

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

Поробовал, по скорости тоже самое, более того, уменьшил частоту обновление до 500мс всё равно долго запускает alert. Сначала долго тупит потом вываливает сразу много строк успешного запуска. Как буд-то забивается турба, а потом «прорвало».

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

Пример на bash сможете организовать?))

Я не знаю, какие у вас данные, и в каком формате они выводятся. Предполагая, что выводится переменное количество действительных чисел в строке, разделённых любым числом пробелов и/или табуляций, создал такой тестовый файлик test_nums.txt (данные взял из верхнего поста, добавив последнюю строчку для пограничных случаев):

12.454398734      -32.39841032                     88.382397873
-34.12312344    555.12343442            -22.42342344
-100.0000   100.0   -100.000000001 +100.0001

Ну и написал такой «скрипт» (точнее, однострочник):

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

Команда cat просто выводит исходные данные вместо вашей «prog», команда sed заменяет все цепочки из неограниченного числа пробелов и табуляций на символ новой строки, и, наконец, команда awk выводит 1-ое полученное слово (а получает она после предыдущей обработки всегда 1 слово в строке) и ": " без перевода строки, затем сравнивает с диапазоном [-100,+100] и выводит «Ok» или «alert» с переводом строки (поэтому в первом случае используется printf, а во втором — print).

без awk обновляется мгновенно, то есть вывод в реальном времени как и без jq.

и

Сначала долго тупит потом вываливает сразу много строк

Да, похоже на задержку из-за буферизации. Странно, что не помог fflush(). Но fflush вызывается в awk. Может там jq тупит? Попробуйте мой вариант без него.

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

заменил ваш вариант awk на вариант от beastie в одноу строку, а так же попробовал вариант:

./prog |\
    sed 's/[\t ]\+/\n/g' |\
    awk '$1 > 100 || $1 < -100 { print; fflush(); }' |\
    xargs -n1 ./alert

В обоих случаях есть задержка, хотя с чистым sed всё мгновенно. Всё таки это awk тормозит.

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

xargs запуститься только когда будут какие-то выходные данные от awk? то есть он будет запускать alert каждый раз когда есть совпадение с фильтром. А как правильно закончить выполнение сценария? Например:

...
xargs -n1 ./alert && exit "$?"

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

WildUser ()