Остановите эхо и используйте весь пользовательский ввод в Bash

TARGET

Пока некоторая подзадача в скрипте не завершит свою работу:

  • остановить эхо;
  • отключить курсор;
  • потреблять весь пользовательский ввод;
  • не блокируйте прерывания (Ctrl+C и т. д.).

ЧТО СДЕЛАНО

Сейчас, используя этот ответ, я создаю несколько функций для этого, вот они:

function hide_input()
{
  if [ -t 0 ]; then
    stty -echo -icanon time 0 min 0
  fi
}

function reset_input()
{
  if [ -t 0 ]; then
    stty sane
  fi
}

function stop_interactive()
{
  trap reset_input EXIT
  trap hide_input CONT
  hide_input
  tput civis
}

function start_interactive()
{
  tput cnorm
  reset_input
}

function consume_input()
{
  local line
  while read line; do line=''; done
}

И вот как они используются:

echo "Warn the user: the job will be started."
read -p "Continue? [yes/no] > "
if [ "$REPLY" == "yes" ]; then
  stop_interactive  # <== from here all input should be rejected
  echo "Notify the user: job starting..."

  # << ------ here goes some long job with output to terminal ------>

  echo "Notify the user: job done!"
  consume_input # <== here I trying to get all user input and put nowhere
  start_interactive # <== from here restore normal operation
else
  echo "Aborted!"
  exit 0
fi

ЭТА ПРОБЛЕМА

Проблема в том, что текущее "решение" не работает. Когда я нажимаю клавиши во время длительного выполнения задания, они появляются на экране, а нажатие клавиши "Ввод" уничтожает весь вывод движениями курсора. Кроме того, после вызова функции "start_interactive" весь ввод появляется на экране терминала.

Каково правильное решение для этой задачи?

РЕШЕНИЕ

Окончательное рабочее решение:

function hide_input()
{
  if [ -t 0 ]; then
    stty -echo -icanon time 0 min 0
  fi
}

function reset_input()
{
  if [ -t 0 ]; then
    stty sane
  fi
}

function consume_input()
{
  local line
  while read line; do line=''; done
}

function stop_interactive()
{
  trap reset_input EXIT
  trap hide_input CONT
  hide_input
  tput civis
}

function start_interactive()
{
  consume_input
  trap - EXIT
  trap - CONT
  tput cnorm
  reset_input
}

echo "Warn the user: the job will be started."
read -p "Continue? [yes/no] > "
if [ "$REPLY" == "yes" ]; then
  stop_interactive
  echo "Notify the user: job starting..."
  do_the_job &
  pid=$!
  while ps $pid > /dev/null ; do
    consume_input
  done
  echo "Notify the user: job done!"
  start_interactive
else
  echo "Aborted!"
  exit 0
fi

1 ответ

Решение

Исходя из вашего вопроса, возникает много вопросов "почему", если я смотрю на ваш код. Если вы не хотите изменять поведение ^C и т. Д., Не используйте ловушки. Все ваши функции проверяют, является ли дескриптор файла 0 терминалом. Планируете ли вы использовать сценарий в трубе? Кроме того, ваше потребление пользовательского ввода будет продолжаться до конца файла, поэтому сценарий может никогда не закончиться.

Исходя из вашего вопроса, я бы написал что-то вроде этого:

echo "Warn the user: the job will be started."
read -p "Continue? [yes/no] > "
if [ "$REPLY" == "yes" ]; then
    stty -echo
    echo "Notify the user: job starting..."
    program_to_execute &
    pid=$!
    while ps $pid > /dev/null ; do
        read -t 1 line
    done
    echo "Notify the user: job done!"
else
    echo "Aborted!"
fi
stty sane
Другие вопросы по тегам