LINUX.ORG.RU
ФорумAdmin

пернаправление ввода

 ,


0

2

Это попытка решить проблему, которую пытался решить в предыдущих темах.
Есть скрипт на BASH, в котором я перехватываю сигналы:

# Перехватываем сигналы.
 # Завершение работы, сигнал "TERM".
 trap 'vozvrisxzn ; exit 0' SIGTERM
 # Завершение работы, сигнал посланный комбинацией клавиш Ctrl+c.
 trap 'vozvrisxzn ; exit 0' SIGINT
 # Отправка в фон - нажатие Ctrl+z.
 trap 'vozvrisxzn' SIGTSTP
 # Возврат из фона - набор в консоли bg или fg.
 trap 'izfona' SIGCONT
 # Изменение размеров терминала во время работы программы.
 trap 'izmrazmterm' SIGWINCH

Этот код стоит в начале скрипта. Далее после некоторого выполнения скрипта (он выводит некоторую информацию в терминал) он останавливается и ждёт нажатия клавиш командой read. Если вместо read сделать бесконечный пустой цикл, то сигналы обрабатываются сразу. Например после изменения размеров графического эмулятора терминала, выведенная информация отлично подстраивается под изменившиеся размеры терминала. Когда же мы ждём нажатия клавиш командой read, то после изменения размеров терминала обработка этого сигнала происходит только тогда когда мы нажмём какую нибудь клавишу, то есть только тогда когда отработает команда read. Получается, что обработка сигналов происходит только после окончания выполнения команды во время которой пришёл сигнал. Поставить маленькое время ожидания read (например -t 0.5 секунд) я не могу, мне же надо что бы сигналы обрабатывались сразу или хотя бы с маленькой задержкой, но не после тога как я нажму на клавишу.
Вариант вижу только один (да и то я не уверен что это можно сделать), read сделать в отдельной функции например fynk() и эту функцию запускать в фоне. Получится так что запуститься дополнительный экземпляр bash с этой функцией, его pid я могу узнать, получаем вот такой код:

fynk &
PIDFYNK=$!

Теперь вопрос и трудность вот в чём, можно ли как то перенаправить ввод с клавиатуры то есть перенаправить стандартный входной поток (дескриптор файла 0) в этот процесс, функцию fynk и команду в этой функции read? Если можно то как это сделать?
Получается так что у меня на терминал выводит один процесс, а клавиатура должна перенаправляться в процесс работающий в фоне.
Думаю если так сделать можно, то и сигналы будут обрабатываться быстро, так как у меня в процессе запущенном непосредственно в терминале не будет команды read.
За помощь буду заранее благодарен!

★★

можно ли как то перенаправить ввод с клавиатуры то есть перенаправить стандартный входной поток (дескриптор файла 0) в этот процесс,

Так это и так делается. Дочерний процесс получает дескрипторы родительского.

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

Так это и так делается. Дочерний процесс получает дескрипторы родительского.

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

v4567 ★★
() автор топика

Фоновый процесс вроде отсоединяется от терминала.

В любом случае используй неблокирующий read.

anonymous
()

А у вас случайно до этого не завершился некорректно какой-нибудь процесс, работающий с терминалом посимвольно? Ведь по умолчанию всё что вы описали выглядит очень странно, и, я вот, совершенно понятно, повторить не могу: все сигналы срабатывают и внутри read как обычно - сразу.

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

В любом случае используй неблокирующий read.

Это со временем ожидания: read -t 1 ?

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

А у вас случайно до этого не завершился некорректно какой-нибудь процесс, работающий с терминалом посимвольно?

нет

Ведь по умолчанию всё что вы описали выглядит очень странно, и, я вот, совершенно понятно, повторить не могу: все сигналы срабатывают и внутри read как обычно - сразу.

Приведите пример кода, я попытаюсь повторить.

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

Приведите пример кода, я попытаюсь повторить.

Вообще-то это вы должны пример приводить. Ну да ладно, мне не трудно:

echo_sig() {
        echo signal detected
}

trap 'echo_sig' SIGTERM
trap 'echo_sig' SIGINT
trap 'echo_sig' SIGTSTP
trap 'echo_sig' SIGCONT
trap 'echo_sig' SIGWINCH

while read -t 2 l; do
        echo "=$l="
done

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

Вот такая конструкция уже не работает.

#!/bin/bash


echo_sig() {
        echo signal detected
}


otlovkeys()
{

 while [ true ]
  do

    KEY=""
    zaderjka=""

    for (( i=0 ; i<10 ; i++ ))
     do
       eval $( (IFS="" read -r -s -n 1 $zaderjka key ; printf 'code %d' "'$key") 2>&1 | awk 'NR==1||NR==4 {print $1 "=" $2}' )
       if [ "$code" != "0" ] || [ "$code" = "0" -a "$zaderjka" = "" ]
        then
            KEY=$KEY$code
       fi
       zaderjka="-t 0.01"
    done

    case $KEY
     in
       # Клавиша Esc.
       27)
          echo "2222222222233333333333"
          ;;
       # Клавиша F1.
       277980)
              ;;
       # Клавиша Стрелка вверх и Меню+Стрелка вверх.
       279165)
              ;;
       # Клавиша Стрелка вниз и Меню+Стрелка ввниз.
       279166)
              ;;
       # Клавиша Стрелка влево и Меню+Стрелка влево.
       279168)
              echo "2222222222211111111111"
              ;;
       # Клавиша Стрелка вправо и Меню+Стрелка вправо.
       279167)
              ;;
       # Клавиша Ctrl+Стрелка вверх.
       279149595365)
                    ;;
       # Клавиша Ctrl+Стрелка вниз.
       279149595366)
                    ;;
       # Клавиша Ctrl+Стрелка влево.
       279149595368)
                    ;;
       # Клавиша Ctrl+Стрелка вправо.
       279149595367)
                    ;;
       *)
         ;;
    esac

 done

 return 0

}


trap 'echo_sig' SIGTERM
trap 'echo_sig' SIGINT
trap 'echo_sig' SIGTSTP
trap 'echo_sig' SIGCONT
trap 'echo_sig' SIGWINCH

while [ true ]
 do

   otlovkeys

done

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

zaderjka

Пиши отладочные сообщения в gurnal

otlovkeys

feispalma.jpg

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

Вы хотите, чтобы за вас написали эту игрушку?

.....
otlovkeys()
{
 oldIFS=$IFS
 while [ true ]
  do

    KEY=
    timeout=

    for (( i=0 ; i<10 ; i++ ))
     do
       code=
       read -r -s -n 1 $timeout key && printf -v code '%d' "'$key"
       [ -n "$code" ] && KEY=$KEY$code
       timeout="-t 0.01"
    done

    case $KEY
......

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

Вы хотите, чтобы за вас написали эту игрушку?

Нет. Пишу сам и одновременно разбираюсь, углубляясь в теме и информации. А здесь спрашиваю о том, в чём не могу разобраться.

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

Ну так последний пример начала функции otlovkeys() работает или как? У вас же там было посимвольное чтение в подпроцессе, потому основной процесс и не мог получить сигналы.

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

Ну так последний пример начала функции otlovkeys() работает или как? У вас же там было посимвольное чтение в подпроцессе, потому основной процесс и не мог получить сигналы.

Да Ваш пример работает.

Код который я использовал, взял вот отсюда: Арканоид

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

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

Лучше называй методы/переменные на русском. Хоть так.

Некоторые я называю русскими названиями но пишу латиницей. В bash ведь нельзя дать названия переменным и функциям кириллицей?

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

Непонятными остался вот какой вопрос. Зачем в «'$key» одинарная кавычка?
И ещё хотелось бы уяснить вот какой момент. Когда в скрипте запустит фоновый процесс потомок, то он получить дескрипторы родительского процесса. Поэтому вывод будет идти в терминал в котором запущен родитель, а вот ввод не получается направить в фоновый процесс, хотя он должен направляться туда и так.

Вот этот код работает нормально:

#!/bin/bash
funk()
{
sleep 20
echo "1111111111111111111"
}

funk &

while [ true ]
 do
   sleep 0
done

Видно два процесса, по истечении 20 секунд выводятся единицы и второй процесс исчезает.

а вот этот код не работает:

#!/bin/bash
stty -echo
funk()
{
read -s str
echo $str
}

funk &

while [ true ]
 do
   sleep 0
done

второй процесс не порождается вообще.

Если взять конструкцию read из нашего примера, то там порождается то два то три процесса, почему то очищается экран и всё равно не работает. Причём из терминала в котором запускается скрипт его по ctrl+c не убить.

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

Код который я использовал, взял вот отсюда: Арканоид

Но не совсем. Там были измерения времени чтения, у вас только чтение.

Могу сказать только, что тот который взял порождает несколько процессов потомков

Вообще-то я вам именно это и сказал

Зачем в «'$key» одинарная кавычка?

Это такой фокус у printf, перевести символ в число.

а вот ввод не получается направить в фоновый процесс,

Потому что ввод с терминала фоновым процессом при проектировании Unix посчитали нежелательным, так как это может случайно перемешать что достанется основному, а что - фоновым процессам, поэтому фоновые процессы при такой попытки — останавливаются.

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

это встроенная в баш команда, которая ничего не делает

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

зачем это, когда есть
while :

Я настолько стар, что знаю, для чего раньше использовался ':' и использовал это, потому эти фокусы с «while :» не очень то мне по душе. Интересно, сколько народу могут правильно интерпретировать, что означает на самом деле «while [ true ]»? :))

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

знаю, для чего раньше использовался ':'

для чего?

и эти фокусы с «while :» не очень то мне по душе

от чего же? сейчас же эта команда ничего не делает

Интересно, сколько народу могут правильно интерпретировать, что означает на самом деле «while [ true ]»?

а что тут интерпретировать? скобки — это test, который проверяет с каким кодом возврата завершилась программа true, которая всегда возвращает true, поэтому скобки не нужны

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

для чего?

Вы не поверите, но до 90-х в bourne-shelle, как и во многих языках это таки были метки! Они даже работали.

а что тут интерпретировать?

Я так и знал — незачёт. С каких пор test вызывает какие-либо команды?

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

действительно, не вызывает.
а что же он делает? [ false ] и любое другое слово в скобках срабатывает также

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

а что же он делает?

Пример на самом деле не сложный, просто он составлен, чтобы запутать. Напрягитесь. Почитайте man test...

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

Потому что ввод с терминала фоновым процессом при проектировании Unix посчитали нежелательным, так как это может случайно перемешать что достанется основному, а что - фоновым процессам, поэтому фоновые процессы при такой попытки — останавливаются.

Это возможно как то сделать или вообще нельзя?
И ещё вот какой вопрос.
Если осуществлён вход двух разных пользователей в систему. Не важно как, например один вошёл непосредственно с терминала, а другой по ssh, или наоборот.
Можно ли как то направить вывод первого пользователя второму, что бы при этом вывод первого остался и в его терминал? И ввод второго пользователя направить в вод первого?

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

Кстати если взять вот такой вот код:

#!/bin/bash


echo_sig() {
        echo signal detected
}



trap 'echo_sig' SIGTERM
trap 'echo_sig' SIGTSTP
trap 'echo_sig' SIGCONT
trap 'echo_sig' SIGWINCH

while [ true ]
 do
   sleep 10

done

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

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

Вы не поверите, но любой сетевой протокол примерно так и работает, общается с системой на уровне root, потом может поменять пользователя на указанный в протоколе пользователя/сертификата/etc. При этом другая сторона на том конце сети думает, что работает с терминалом. Этот фокус называется - псевдотерминалы. /dev/pt{y,s}* Вот только просто так на высоком уровне типа bash с псевдотерминалами вряд ли получится поработать. Там слишком много приходится программировать на низком уровне.

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

так как лучше писать: while :, while [ true ], while [ -n true ] или while true ?
И ещё в ветвлении как лучше писать: if [ условие ] или if [[ условие ]] ?

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

то сигналы будут отрабатывать не сразу, а после завершения очередного sleep

может, вынести строки с trap в дочерний процесс в фоне? не знаю, будет ли работать

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

а если два пользователя вошли с терминалов, один непосредственно, а другой по com порту через устройство (например «крон»), возможно тогда перенаправить выводы и вводы?

Если на одном компьютере открыть два эмулятора терминалов, то это ведь то же будут псевдотерминалы и между ними получается перенаправить вводы и выводы будет то же очень трудно?

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

может, вынести строки с trap в дочерний процесс в фоне? не знаю, будет ли работать

сейчас попробую.

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

Сделал так:

#!/bin/bash


echo_sig() {
        echo signal detected
}


fynk()
{

trap 'echo_sig' SIGTERM
trap 'echo_sig' SIGTSTP
trap 'echo_sig' SIGCONT
trap 'echo_sig' SIGWINCH

}

fynk &

while [ true ]
 do
   sleep 10

done

Вообще не работает.

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

Перенаправить ввод удалось вот таким образом:

#!/bin/bash

stty -echo

funk()
{

 read -s str
 echo $str

}

funk <&0 &

while [ true ]
 do
   sleep 0
done

Ключевой момент: funk <&0 &

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

так как лучше писать: while :, while [ true ], while [ -n true ] или while true ?

Так как true встроенная команда, то while true писать самое правильное, хотя бы потому, что вдруг понадобится написать false.

if [ условие ] или if [[ условие ]] ?

[[ - раслабляющий башизм. Привыкните, потом трудно будет писать без него. :)

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

Если вам просто данные перекачивать, то для этого существуют всякие pipe и прочие сетевые протоколы. А вот если вам настоящий терминал эмулировать, с прерываниями, то без программирования с псевдотерминалами не обойтись, так как вы же понимаете, что сигналы, скажем на изменение размера окна - они локальны, а передать надо в другую сторону трубы. Нужно, чтобы мастер-процесс работал с мастером-терминалом, разбирал что передаётся и в зависимости от, или пересылал данные или управлял подчинёнными процессами.

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

Если вам просто данные перекачивать,

Просто данные.

Вошли в систему два пользователя, одному из них нужно видеть что вводит второй и что у второго выводится на терминал. Соответственно, (для помощи второму) один вводит команду, а она вводится у второго на терминале и выполняется у второго на терминале и выводит данные у второго пользователя при этом первый видит вывод.

Вот это интересует как сделать в bash. Я знаю, да и пробовал это делать в screen. А вот в bash не знаю как это сделать.

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

Вы злоупотребляете. Намёк был вполне прозрачный.

Если бы я знал досконально bash может быть бы и понял намёк.

В одних статьях пишут что лучше писать [[ но в подавляющем большинстве пишут [.

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

Вошли в систему два пользователя, одному из них нужно видеть что вводит второй и что у второго выводится на терминал

Воот, таки терминал. А то что данными обмениваетесь, то тут надо определиться - данные формирутся пользовательсткими программами или пользователем и системой. Если программами, то это всё просто, рисуете протокол чатика, и программируете его на трубах или на сети.

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

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

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

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

Если сильно упростить задачу, то можно и на bash. Но это я себе представляю так: сервер чатика, к нему подключаются N пользователей, но они обмениваются не сообщениями, а строкой, которая будет запущена на сервере, а результат - будет выведен обоим. Отсюда вытекает, что работать будет на простых командах, всякие редакторы текста работать не будут. Даже bash на сервере работать не будет в интерактивном режиме, так как каждую команду придётся запускать отдельным неитерактивным вызовом bash -c «строка».

Для контролем за аутсорсерами, что они там «понажимали» мы юзаем софт «Балабит». Оно записывает в свой формат мультика, что нажимают, понимает rdp и ssh.

vodz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.