Zsh: таймаут для встроенной команды vared

Вопрос или проблема

У меня есть цикл while, который использует vared для запроса ввода от пользователя. Я ищу способ установить время ожидания, выполнить значение по умолчанию и вернуться к запросу, если пользователь не вводит данные после определенного времени. Я знаю о команде read и ее аргументе timeout, но возможно ли это каким-либо образом с vared?

Кроме того, есть ли способ установить значение по умолчанию для vared, которое не будет выводиться на запрос?

local command

while :

   do
     echo "Введите команду или наберите 'quit' для выхода:"
     vared -p "[*]: " command

     if [ "$command" = "quit" ]; then
         break

     else
         run command
     fi

     clear

   done

Вы могли бы сделать что-то подобное:

default=foobar
if
  command=$(
    saved_settings=$(stty -g)
    trap 'stty $saved_settings; exit 1' ALRM
    v=
    TMOUT=10 vared -p "Введите команду [$default]: " v &&
      printf %s $v
  )
then
  command=${command:-$default}
  printf 'Получено: "%s"\n' $command
else
  print таймаут
fi

Вместо того чтобы инициализировать переменную значением по умолчанию, мы инициализируем ее пустой строкой и только устанавливаем значение по умолчанию, если переменная все еще пуста после того, как vared вернет результат.

Чтобы обработать таймаут, мы используем специальную переменную $TMOUT в дочерней оболочке, что приводит к выходу zle из этой дочерней оболочки после $TMOUT секунд.

Это глобальный таймаут в 10 секунд. Другой подход может заключаться в использовании дисциплины терминала для таймаута между символами (stty time x, где x выражается в десятых долях секунды), чтобы дать пользователю достаточно времени для ввода большой команды, но с таймаутом, скажем, после 3 секунд неактивности:

default=foobar
if
  command=$(
    saved_settings=$(stty -g)
    trap 'stty $saved_settings' EXIT INT TERM ALRM
    zle-line-init() stty -icanon time 30 min 0 <&2
    zle -N zle-line-init
    v=
    vared -p "Введите команду [$default]: " v &&
      printf %s $v
  )
then
  command=${command:-$default}
  printf 'Получено: "%s"\n' $command
else
  print
  print таймаут
fi

Обратите внимание, что хотя эти решения работают в скриптах, в интерактивных оболочках это в настоящее время не работает, так как vared отказывается работать в дочерних оболочках. Если вам нужно запустить это из интерактивной оболочки, пока это не будет исправлено в zsh, вы можете изменить:

command=$(
  ...
)

На

command=$(default=$default zsh -c '
  ...
')

Ответ или решение

В Zsh, чтобы реализовать таймаут для команды vared, вы можете использовать специальную переменную TMOUT, которая устанавливает глобальный тайм-аут на ввод. Однако, так как vared не может быть использован в подсчетах, вызванных подшеллами в интерактивном режиме, задача немного усложняется. Вот метод, который вы можете использовать, а также способы установить значение по умолчанию без его отображения в приглашении.

Реализация таймаута для vared

  1. Использование переменной TMOUT:

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

default=foobar
if command=$(
  saved_settings=$(stty -g)
  trap 'stty $saved_settings; exit 1' ALRM
  v=
  TMOUT=10 vared -p "Введите команду [$default]: " v && printf %s $v
)
then
  command=${command:-$default}
  printf 'Получено: "%s"\n' $command
else
  print "Таймаут"
fi

В этом коде, если пользователь ничего не введет в течение 10 секунд, будет выведено сообщение о таймауте, а переменная command будет установлена в значение $default.

  1. Настройка таймаута через терминал:

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

default=foobar
if command=$(
  saved_settings=$(stty -g)
  trap 'stty $saved_settings' EXIT INT TERM ALRM
  zle-line-init() stty -icanon time 30 min 0 >&2
  zle -N zle-line-init
  v=
  vared -p "Введите команду [$default]: " v && printf %s $v
)
then
  command=${command:-$default}
  printf 'Получено: "%s"\n' $command
else
  print "Таймаут"
fi

В данном примере, если пользователь не введет ничего в течение 3 секунд (или 30 десятых долей секунды), будет вызван таймаут.

Установка значения по умолчанию без отображения

Чтобы установить значение по умолчанию, не выводя его в приглашение, вы можете просто использовать переменную v в vared и затем обработать её после ввода:

default=foobar
v=
vared -p "Введите команду: " v
command=${v:-$default}
printf 'Получено: "%s"\n' "$command"

В этом примере, значение переменной v будет использовано, если пользователь введёт что-то. Если пользователь оставит пустую строку, команда command будет установлена на значение переменной $default.

Заключение

Таким образом, вы можете реализовать таймаут для vared, а также устанавливать значение по умолчанию без его отображения в приглашении. Будьте внимательны, что указанные методы могут работать не во всех интерактивных оболочках из-за ограничений, связанных с запуском vared в подсчетах, но они должны выполняться корректно в большинстве сценариев.

Оцените материал
Добавить комментарий

Капча загружается...