непонятное поведение скрипта

На самом деле это единственный раздел про unix на этом форуме

Модератор: /dev/random

v4567
Сообщения: 145
ОС: Devuan

непонятное поведение скрипта

Сообщение v4567 » 11.08.2019 14:53

Здравствуйте форумчане.

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

Есть вот такой скрипт:

Shell

#!/bin/bash


klav()
{

exec 2>&-

local ppid KEY key code timeout i

while true
do
KEY=
timeout=
i=0
while [[ "$i" -lt 10 ]]
do
code=
read -r -s -n 1 $timeout key && printf -v code '%d' "'$key"
[ -n "$code" ] && KEY=$KEY$code
timeout="-t 0.01"
(( i++ ))
done
case "$KEY"
in
27)
echo -e "\e[32mЗАВЕРШЕНИЕ РАБОТЫ\e[0m"
sleep 1
reset
clear
echo -en "\e[0m\e[?25h"
stty echo
ppid=$$
kill -TERM "$ppid"
exit 0
;;
*)
echo "111111111"
;;
esac
done
}

stty -echo


klav <&0 &

clear
#reset

echo -en "\e[?25l"


while true
do
:
done
Работает всё прекрасно. После нажатия клавиши "Esc" скрипт завершает свою работу, если нажимать другие клавиши, например буквы то выводится строка "111111", как и задумывалось клавишу "Enter" нажимать при этом не надо.
Но стоит раскомментировать команду reset и скрипт начинает работать по другому.
Появляется это, ну это понятно ведь мы сбросили настройки. Далее идут вещи мне не понятные. Команда:

Shell

echo -en "\e[?25l"
срабатывает не сразу, курсор перемещается в левый верхний угол и исчезает через секунду или полторы. Если закомментировать reset то всё происходит мгновенно.
По нажатию клавиши "Esc" скрипт не завершается, а на экран выводится ^[, при нажатии на клавиши букв строка "111111111" не выводится, выводятся символы латинских букв и только после нажатия клавиши "Enter" всё начинает работать нормально - как и было задумано. Если "Enter" нажать самым первым то работет всё то же нормально как и задумано. Получается reset меняет работу скрипта, теперь надо нажать "Enter" что бы всё работало нормально.
Почему так?

И ещё один вопрос.
Основной скрипт порождает потомок - этот же скрипт в котором выполняется функция
"klav" при завершении основного скрипта потомок ведь должен завершиться сам, но этого не происходит, его приходится завершать командой exit 0 Почему так то же не пойму.

И ещё хотел бы узнать можно как то передать в функцию klav переменные или значения переменных из основного скрипта, а так же передать переменные из этой функции klav в основной скрипт. Знаю, что это можно сделать через глобальные переменные, но говорят, что это не правильно, надо делать через eval. Но как это делать через eval не знаю, знаю только как при помощи этого eval раскрыть переменную два и более раз - это когда значение переменной есть название ещё одной переменной.

Всё проверял в текстовой консоли работающей поверх ядерного фреймбуфера, а так же в графическом эмуляторе терминала kde -> konsole

Может быть вопросы просты и наивны, но ответов на них я не знаю и не нашёл.
Если кто знает объясните пожалуйста.
Спасибо сказали:

Аватара пользователя
ormorph
Сообщения: 907
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение ormorph » 11.08.2019 18:20

v4567 писал:
11.08.2019 14:53
Появляется это, ну это понятно ведь мы сбросили настройки. Далее идут вещи мне не понятные. Команда:
Хм не верно, вы сбросили терминал, значения переменных остались теми же, а так как у вас функция klav выполняется в фоне, то соответственно она не доступна пока не нажмешь enter.
А так уж больно заумно сделан скрипт, вроде можно сделать проще
Spoiler

Код: Выделить всё

#!/bin/bash

reset

klav()
{

 local ppid KEY key code timeout i

 while true
  do
    KEY=
    timeout=
    i=0
    while [[ "$i" -lt 10 ]]
     do
       code=
       read -r -s -n 1 $timeout key && printf -v code '%d' "'$key"
       [ -n "$code" ] && KEY=$KEY$code
       timeout="-t 0.01"
       (( i++ ))
    done
    case "$KEY"
     in
       27)
          echo -e "\e[32mЗАВЕРШЕНИЕ РАБОТЫ\e[0m"
          sleep 1
          reset
          clear
          echo -en "\e[0m\e[?25h"
          #exit 0
          break
          ;;
       *)
         echo "111111111"
         ;;
    esac
 done
}

klav
reset
его приходится завершать командой exit 0 Почему так то же не пойму.
Не надо было функцию отправлять в фон.
И ещё хотел бы узнать можно как то передать в функцию klav переменные или значения переменных из основного скрипта, а так же передать переменные из этой функции klav в основной скрипт. Знаю, что это можно сделать через глобальные переменные, но говорят, что это не правильно, надо делать через eval. Но как это делать через eval не знаю, знаю только как при помощи этого eval раскрыть переменную два и более раз - это когда значение переменной есть название ещё одной переменной.
В потомок можно передавать переменные и функции, а вот обратно нет, нельзя и с помощью eval, если запущенно в новом процессе bash.
Просто стараться организовывать все в одном процессе, иначе можно передавать значения переменных через каналы fifo либо файлы от потомка к родителю.
Спасибо сказали:

Аватара пользователя
/dev/random
Администратор
Сообщения: 4866
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение /dev/random » 11.08.2019 18:36

v4567 писал:
11.08.2019 14:53
Но стоит раскомментировать команду reset и скрипт начинает работать по другому.
read -n ЧИСЛО переводит терминал в режим побайтового ввода вместо построчного и ждёт поступления данных. Команда reset, если вы её раскомментируете, у вас запускается в другом процессе, работающем параллельно с read, и сбрасывает все настройки терминала (а это именно настройки самого терминала, xterm или что там у вас, а не bash) - включая установленный командой read посимвольный режим, переводя его обратно в построчный. Теперь терминал не отправит программе ничего, пока вы не нажмёте enter.
v4567 писал:
11.08.2019 14:53
при завершении основного скрипта потомок ведь должен завершиться сам, но этого не происходит
Не должен. С чего вы взяли, что должен?
Спасибо сказали:

v4567
Сообщения: 145
ОС: Devuan

Re: непонятное поведение скрипта

Сообщение v4567 » 11.08.2019 18:40

У меня весь фокус в том, что функция работы с клавиатурой запускается в фоне и в основном скрипте мне не надо всё время обращаться к ней. В вашем скрипте, в основном скрипте всё время надо будет обращаться к этой функции для отработки нажатия клавиш.
Может я ошибаюсь, но наверно не имеет значение запущен потомок в фоне или нет, если основной процесс прекратил свою работу то и все потомки должны прекратить, или не так?
Добавлено (18:42):
/dev/random всё понял спасибо!
Добавлено (18:44):
/dev/random подскажите ещё пожалуйста как в функцию klav из основного скрипта передать переменные или их значения и как обратно из функции klav в основной скрипт передать переменные или их значения?
Спасибо сказали:

Аватара пользователя
ormorph
Сообщения: 907
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение ormorph » 11.08.2019 18:55

v4567 писал:
11.08.2019 18:40
У меня весь фокус в том, что функция работы с клавиатурой запускается в фоне и в основном скрипте мне не надо всё время обращаться к ней. В вашем скрипте, в основном скрипте всё время надо будет обращаться к этой функции для отработки нажатия клавиш.
Ни кто не мешает вам запускать данную функцию в родителе в фоне, главное обернуть все в одну функцию, тогда при выходе по exit 0 из родителя, будет завершаться работа данной функции.
Спасибо сказали:

Аватара пользователя
/dev/random
Администратор
Сообщения: 4866
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение /dev/random » 11.08.2019 19:01

v4567 писал:
11.08.2019 18:40
/dev/random подскажите ещё пожалуйста как в функцию klav из основного скрипта передать переменные или их значения и как обратно из функции klav в основной скрипт передать переменные или их значения?
Процессы баша наследуют переменные только в момент запуска, и только от родителя к потомку. После этого весь обмен данными нужно производить через функции ввода-вывода (обычно пайпы, иногда файлы). Так что в вашем случае никакой пользы от выделения read в отдельный процесс нет: всё равно придётся вызывать read в главном процессе для получения данных от фонового.
Спасибо сказали:

v4567
Сообщения: 145
ОС: Devuan

Re: непонятное поведение скрипта

Сообщение v4567 » 11.08.2019 20:46

По поводу потомков.
Когда выйти из системы, если например оболочкой запускался баш, то все потомки прекратят работу. Что бы какой то потомок смог работать далее его надо запускать через nohup. В моём случае функция klav то же запускается как потомок, не пойму почему же она не должна быть остановлена?
И ещё один момент есть ли способ в баше вынести функцию read в другой процесс что бы с этим процессом можно было бы обмениваться данными не прибегая в основном скрипте всё время к обращению определённому куску кода?
Тип работа с клавиатурой имитирующий как бы работу по прерыванию.
Спасибо сказали:

Аватара пользователя
/dev/random
Администратор
Сообщения: 4866
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение /dev/random » 11.08.2019 21:24

v4567 писал:
11.08.2019 20:46
Когда выйти из системы, если например оболочкой запускался баш, то все потомки прекратят работу. Что бы какой то потомок смог работать далее его надо запускать через nohup. В моём случае функция klav то же запускается как потомок, не пойму почему же она не должна быть остановлена?
При закрытии терминала (терминала, а не оболочки) ядро посылает всем запущенным в этом терминале программам сигнал SIGHUP, который убивает программу, если она не повесила на него другое действие. Сам bash тоже умеет в некоторых случаях посылать потомкам этот сигнал, но на вашу ситуацию это не распространяется.
v4567 писал:
11.08.2019 20:46
И ещё один момент есть ли способ в баше вынести функцию read в другой процесс что бы с этим процессом можно было бы обмениваться данными не прибегая в основном скрипте всё время к обращению определённому куску кода?
Тип работа с клавиатурой имитирующий как бы работу по прерыванию.
В теории. Можно повесить обработчик сигнала, запрашивающий данные от фонового процесса, и отправлять этот сигнал каждый раз, когда есть очередная порция данных. Но на практике подводных камней столько, что лучше не пытаться.
Спасибо сказали:

v4567
Сообщения: 145
ОС: Devuan

Re: непонятное поведение скрипта

Сообщение v4567 » 11.08.2019 21:36

Плохо всё это.
В железе есть возможность работать по прерываниям, а программы этого не используют.
На сколько я знаю если писать на Си под систему, то ядро linux то же не предоставляет возможность например для клавиатуры работать по прерываниям. Понятно, что для программ нельзя предоставлять возможность работать с прерываниями, но это ведь можно сделать через ядро. Ядру указать что такие то кнопки нужны для такой то программы когда она работает не в фоне, или даже и в фоне (мало ли может такой вариант то же когда то будет нужен), по прерыванию от клавиатуры ядро получает информацию что нажаты такие то клавиши и передаёт её соответствующей программе, получается так, что программа как бы работает с клавиатурой по прерыванию.
Спасибо сказали:

Аватара пользователя
s.xbatob
Сообщения: 792
ОС: Fedora

Re: непонятное поведение скрипта

Сообщение s.xbatob » 11.08.2019 22:08

v4567
А чего вы хотите? Чтобы система предоставляла всем желающим возможность захватывать общие ресурсы? Так она долго не проживёт.
У процесса нет прямого доступа к какой-либо периферии или к динамической памяти, зато есть механизм запросов к ядру, которое это ему такие возможности предоставляет.
Я так понимаю, вы хотите программу, управляемую событиями, только вы пошли совсем в неправильном направлении, да ещё и инструмент неподходящий избрали. Вот и зашли в тупик почти сразу. Там другая идеология. Но на таком принципе работают все графические программы. Так что на самом деле возможностей ядро предоставляет достаточно.
Спасибо сказали:

Аватара пользователя
ormorph
Сообщения: 907
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение ormorph » 12.08.2019 05:38

v4567 писал:
11.08.2019 21:36
Плохо всё это.
В железе есть возможность работать по прерываниям, а программы этого не используют.
На сколько я знаю если писать на Си под систему, то ядро linux то же не предоставляет возможность например для клавиатуры работать по прерываниям. Понятно, что для программ нельзя предоставлять возможность работать с прерываниями, но это ведь можно сделать через ядро. Ядру указать что такие то кнопки нужны для такой то программы когда она работает не в фоне, или даже и в фоне (мало ли может такой вариант то же когда то будет нужен), по прерыванию от клавиатуры ядро получает информацию что нажаты такие то клавиши и передаёт её соответствующей программе, получается так, что программа как бы работает с клавиатурой по прерыванию.
Вы уж очень глубоко копнули )
Есть такое понятие как уровни абстракции. Как будто по прерыванию int 21h в досе происходит непосредственно обращение к устройству. Там тоже есть свои уровни абстракции.
Спасибо сказали:

v4567
Сообщения: 145
ОС: Devuan

Re: непонятное поведение скрипта

Сообщение v4567 » 12.08.2019 22:17

Хотелось бы узнать ещё один момент. Можно ли как то в скрипт передать поток данных через пайп, что то типа такого команда | баш скрипт?
И ещё, если кто знает где можно почитать хорошую документацию по eval.
По моему в Advanced Bash-Scripting Guide про eval не досказано.

На лоре был пост, (сейчас не могу найти, если найду дам ссылки), там ка то при помощи этого эвала закидывали переменные в функции и вынимали их из функций.
Спасибо сказали:

Аватара пользователя
ormorph
Сообщения: 907
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение ormorph » 12.08.2019 23:08

v4567 писал:
12.08.2019 22:17
Хотелось бы узнать ещё один момент. Можно ли как то в скрипт передать поток данных через пайп, что то типа такого команда
Можно если связать пайп с файлом, либо с каналом fifo. Когда то применял такое для передачи параметров в диалог yad там передача через канал fifo.
И ещё, если кто знает где можно почитать хорошую документацию по eval.

Shell

$ man eval
На лоре был пост, (сейчас не могу найти, если найду дам ссылки), там ка то при помощи этого эвала закидывали переменные в функции и вынимали их из функций.
Это называется передача через файл.
Так как eval эмитирует вводимое в терминале, то достаточно чтобы он выполнил команды прописанные в файле:
Т.е. формируется файл вида:

Код: Выделить всё

A=10
B=20 
это можно передать с помощью echo, допустим файл будет называться dump.
Далее остается выполнить данные команды в принимающем скрипте:

Код: Выделить всё

eval "$(cat dump)"
И всего то, того же можно добиться просто выполнив в принимающем скрипте:

Код: Выделить всё

source dump
Спасибо сказали:

v4567
Сообщения: 145
ОС: Devuan

Re: непонятное поведение скрипта

Сообщение v4567 » 12.08.2019 23:27

У меня вот что:

Shell

man eval
Нет справочной страницы для eval
help eval
eval: eval [аргумент ...]
Выполнение аргументов как команды командного процессора.

Объединяет аргументы в одну строку, результат передаётся
в командный процессор с выполнением полученных команд.

Состояние выхода:
Возвращает состояние выхода команды или успех, если команда пустая.
ormorph За информацию спасибо буду разбираться.
Спасибо сказали:

Аватара пользователя
Bizdelnick
Модератор
Сообщения: 15761
Статус: grammatikführer
ОС: Debian GNU/Linux

Re: непонятное поведение скрипта

Сообщение Bizdelnick » 12.08.2019 23:30

v4567 писал:
12.08.2019 22:17
Хотелось бы узнать ещё один момент. Можно ли как то в скрипт передать поток данных через пайп, что то типа такого команда | баш скрипт?
Можно, в чём проблема-то? read в помощь.
v4567 писал:
12.08.2019 22:17
И ещё, если кто знает где можно почитать хорошую документацию по eval.
По моему в Advanced Bash-Scripting Guide про eval не досказано.
Там нечего досказывать, он делает ровно одну предельно простую вещь.
v4567 писал:
12.08.2019 22:17
На лоре был пост, (сейчас не могу найти, если найду дам ссылки), там ка то при помощи этого эвала закидывали переменные в функции и вынимали их из функций.
Не уверен, что понял, чего Вы хотите, но, возможно, чего-то вроде этого?

Код: Выделить всё

#!/bin/sh

myfunc()
{
  echo VAR=value
}

eval $(myfunc)
echo $VAR
Добавлено (23:31):
v4567 писал:
12.08.2019 23:27

Shell

man eval
Нет справочной страницы для eval
man bash-builtins
Добавлено (23:37):
ormorph писал(а):
12.08.2019 23:08
Можно если связать пайп с файлом, либо с каналом fifo.
Пайп — это и есть канал FIFO. Если же Вы имели в виду именованный канал, то он не даёт ровным счётом ничего по сравнению с неименованным.
Добавлено (23:40):
ormorph писал(а):
12.08.2019 23:08
Это называется передача через файл.
Вот именно файл в этом сценарии совершенно лишний.
Пишите правильно:
в консоли
вкупе (с чем-либо)
в общем
вообще
в течение (часа)
команда
новичок
нюанс
приемлемо
проблема
пробовать
трафик
Спасибо сказали:

Аватара пользователя
ormorph
Сообщения: 907
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение ormorph » 13.08.2019 00:03

Bizdelnick писал:
12.08.2019 23:30
Если же Вы имели в виду именованный канал, то он не даёт ровным счётом ничего по сравнению с неименованным.
В данном случае ему нужно передать данные из одного скрипта в другой, по этому как бы именованный тут будет более уместным, нежели стандартные потоки.
На счет man eval пардон, у меня в Gentoo оно есть в пакете man-pages-posix.
На счет файла, может будет и лишним.
Вроде можно принимать через канал, что то вроде:

Код: Выделить всё

while read command
do
eval "$command"
done <&3
Но этот вариант не тестировал...
Спасибо сказали:

Аватара пользователя
Bizdelnick
Модератор
Сообщения: 15761
Статус: grammatikführer
ОС: Debian GNU/Linux

Re: непонятное поведение скрипта

Сообщение Bizdelnick » 13.08.2019 00:18

ormorph писал(а):
13.08.2019 00:03
В данном случае ему нужно передать данные из одного скрипта в другой, по этому как бы именованный тут будет более уместным, нежели стандартные потоки.
Ну не знаю, я меж строк читать не обучен, а прямо в строке прочёл
v4567 писал:
12.08.2019 22:17
команда | баш скрипт
И не понимаю, чем скрипт так принципиально отличается от любой другой программы, что вот именно для него нужно мусорить в файловой системе и использовать именованные каналы.
Пишите правильно:
в консоли
вкупе (с чем-либо)
в общем
вообще
в течение (часа)
команда
новичок
нюанс
приемлемо
проблема
пробовать
трафик
Спасибо сказали:

Аватара пользователя
ormorph
Сообщения: 907
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение ormorph » 13.08.2019 00:32

Bizdelnick писал:
13.08.2019 00:18
И не понимаю, чем скрипт так принципиально отличается от любой другой программы, что вот именно для него нужно мусорить в файловой системе и использовать именованные каналы.
Ну ему надо передавать данные от потомка к родителю, по этому такое ... используется )
Лично я стараюсь избегать таких скриптов, так как организация работоспособности таких скриптов может быть просто сумасшедшей.
Спасибо сказали:

Аватара пользователя
Bizdelnick
Модератор
Сообщения: 15761
Статус: grammatikführer
ОС: Debian GNU/Linux

Re: непонятное поведение скрипта

Сообщение Bizdelnick » 13.08.2019 00:58

ormorph писал(а):
13.08.2019 00:32
Ну ему надо передавать данные от потомка к родителю, по этому такое ... используется
Из формулировки вопроса это не следует, но если даже так, то в чём проблема?

Код: Выделить всё

while read l; do a="$a $l"; done < <(some_command)
echo $a
На POSIX shell так не сделать, но в bash — запросто.
Пишите правильно:
в консоли
вкупе (с чем-либо)
в общем
вообще
в течение (часа)
команда
новичок
нюанс
приемлемо
проблема
пробовать
трафик
Спасибо сказали:

Аватара пользователя
ormorph
Сообщения: 907
ОС: Gentoo

Re: непонятное поведение скрипта

Сообщение ormorph » 13.08.2019 05:22

Ну это уже топикластеру решать, какое извращение из приведенных выбрать)
Спасибо сказали:

v4567
Сообщения: 145
ОС: Devuan

Re: непонятное поведение скрипта

Сообщение v4567 » 13.08.2019 23:03

Всем спасибо за помощь!
Буду разбираться.
Спасибо сказали: