LINUX.ORG.RU

Как писать интерактивные консольные программы?

 ,


1

2

Доброго времени суток

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

Думаю сделать так:

  • отдельная процедура ask_human() выполняет неблокирующее чтение с консоли и парсинг того, что ввёл пользователь. На выходе 2 строки - управляющее воздействие ( continue, break, status ) и задача, которую нужно выполнять ( task1, task2 и т.д. )
  • в основном цикле программа будет выполнять ask_human() и sleep. Если команда получена - выполнение соответствующей задачи
  • в процедурах задач есть свой цикл, в котором так же выполняется ask_human(). Если получена новая команда - возврат в основной цикл.

Норм? Или есть best practice / pattern, больше подходящий для данной задачи?

Update. Всем спасибо, остановился на варианте с отдельным потоком

★★★★★

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

У меня пока даже proof of concept нет, чтоле

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

По твоему тексту нихрена не понятно какой уровень интерактивности тебе нужен. Если тебе просто нужно «ставить на паузу вычисления», «сохранять результат на диск» и «завершать всё к хренам», то тебе обработки сигналов хватит. Что-то сложное и сильно интерактивное (привет mc) – это TUI, гугли туда :)

Stil ★★★★★
()
vjobivat {}

sdelat_zaebis{}

stop{}

main {
  some_init() // общее состояние и приколяхи

  tread { // читаем комманды от юзера, к примеру по телнету
    loop {
      c = read_user_command()
      case c == "zaebis plz":
        sdelat_zaebis()
      case c == "stop":
        stop()
    }
  }

  tread { // обработчик по таймеру
    loop {
      vjobivat()
      sleep(60) 
    }
  }

  lock
}
iu0v1
()
Ответ на: комментарий от iu0v1

Т.е. опрашивать пользователя в отдельном потоке, а основной поток получит данные в общих переменных? Да, пожалуй так удобнее

Спасибо!

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

Думаю сделать так:

похоже на движок MUD-ов (серверов; или см. муд-клиенты, например tinyfugure, тоже похоже, только таймер с alarm и тикером через сигналы)

Или есть best practice / pattern, больше подходящий для данной задачи?

есть даже такое: Glulx VM, виртуальная машина для Interactive Fiction (текстовые игры типа Zork от Infocom, Level9 и прочих) : см. например нода/тупоскрипт/браузер, интерпретаторы Z-машин

cм. например Inform7 — среду и конкретно расширение к нему Lines of communication, вот этот пример

в исходнике примера в текстовой адвентюре, компилируемой в .z8/.glorb файл с «игрой» для Z-machine/Glulx VM виртуальной машине происходит следующее:

* человек играет с роботом в шахматы
* команды вводит в интерпретатор игрофайла, player -> они передаются дальше по процессам
* часть команд обрабатывает сам движок игры (на основании движка правил, rulebook (типа такого)
* другая часть передаётся для внешнего интерпретатора как stdin и stdout скрипта

(как-то так можно и xchess/gnu chess прикрутить, например, и gui)

Норм? Или есть best practice / pattern, больше подходящий для данной задачи?

предусмотри:

1. запуск через nohup, неинтерактивный в логи которые можно посмотреть tail-ом

2. сигналы, которые можно послать демону kill-ом (в скрипте нужны trap на эти сигналы, обработку)

3. выход из repl-а.

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

да, через потоки или сопрограммы.

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

или процессы с fork-ом и сигналы между родителем и предками.

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

The File of chess-input is called «chessInput». The File of chess-output is called «chessOutput».

The chess computer is a real-time file channel. The input file is File of chess-input. The output file is File of chess-output.

через файлы. или можно через пайпы сделать, как скрипты через | склеиваешь.

anonymous
()

top, htop, tmux ...

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

Т.е. опрашивать пользователя в отдельном потоке, а основной поток получит данные в общих переменных?

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

Еще можно через процессы, обернув в что-то (parent<->fork). Но мне это всегда казалось громоздким.

iu0v1
()

заодно вместо bash посмотри язык Icon/Unicon. там есть треды, мутексы, сигналы и сопрограммы (те же Occam-процессы и каналы), при этом довольно простой переход от скриптоты к конкурентному коду

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

Не то чтобы сильно сложное, но аппетит приходит во время еды и скорее всего сигналов рано или поздно не хватит

Насчёт tui это мысль, скорее всего что-то вроде ncurses пригодится

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

Выглядит интересно, но я не программист и для меня это overkill

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

Всем спасибо, остановился на варианте с отдельным потоком

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

Чем плох демон/сервер реализующий основную функциональность и клиент, функция которого - работать с пользователем?

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

Кмк, это много проще, чем то, что он пытается придумать.

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

тогда посмотри как устроены джаббер-боты или даже irc-боты (ii — консольный irc в несколько строчек с проекта suckless.org)

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

эх, я уж думал язык какой-то новый прикольный)

loz ★★★★★
()

я писал на Perl+Mojo. с минималистичным веб-интерфейсом. Можешь поглядеть в эту сторону.

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