Как я могу изменить вывод скрипта Bash, ожидая ввода пользователя? - PullRequest
0 голосов
/ 22 января 2019

Я хочу построить секундомер в Bash с функцией паузы.Он должен отображать увеличивающийся счетчик, как этот , но останавливать его, когда я нажимаю клавишу «p».

Как мне это реализовать?Если я жду ввода пользователя с помощью read, я не могу обновить счетчик на экране одновременно.Размещение read внутри цикла с тайм-аутом - мой лучший план, но нетривиально использовать тайм-аут менее одной секунды, что мне и нужно.(Это не поддерживается read или GNU timeout.) Прерывания будут работать, но я бы хотел поддерживать произвольные ключи, такие как "p" и "x".

Есть ли достаточно простой способдостичь этого?

Ответы [ 3 ]

0 голосов
/ 23 января 2019

Печать на консоль в ожидании ввода пользователя

  1. Напишите одну функцию, которая создает вывод (например, с: counter или, если вам нравится spin).
  2. Напишите одну функцию для чтения в пользовательских командах (readCommand)
  3. Вызовите обе функции в цикле
  4. Установите тайм-ауты так, чтобы нажатия клавиш читались достаточно быстро.(sleep .1 и read -t.1)
function readCommand(){
   lastCommand=$1
   read -t.1 -n1 c;
   if [ "$c" = "p" ]
   then
     printf "\n\r"; 
     return 0
   fi
   if [ "$c" = "g" ]
   then
     printf "\n\r"; 
     return 1
   fi
  return $lastCommand
}

function spin(){
    for i in / - \\ \| ;
        do 
            printf "\r$i"; 
            sleep .1;
        done
}

function countUp(){
    currentCount=$1
    return `expr $currentCount + 1`
}

function counter(){
    countUp $count
    count=$?
    printf "\r$count"
    sleep .1;
}

command=1
count=0
while : 
do 
   if [[ $command == 1 ]]
   then
      counter
   fi
   readCommand $command
   command=$?
done 

Счетчик остановится, если пользователь нажмет 'p', и продолжит работу, если пользователь нажмет 'g'

0 голосов
/ 28 января 2019

Простой скрипт с файловым дескриптором и простым перенаправлением ввода, не оставляющий временных файлов для очистки.Ожидание выполняется с помощью read параметра -t.

counter() {
        while ! read -t 0.05 -n1 _; do
                printf '\r\t%s' "$(date +%T.%N)"
        done
}

{
        IFS= read -p "Your name, Sir?"$'\n' -r name
        echo >&3
} 3> >(counter "$tmp")

echo "Sir $name, we exit"

Пример вывода:

Your name, Sir?
    2:12:17.153951623l
Sir Kamil, we exit
0 голосов
/ 22 января 2019

Я внес изменение в код, который вы ссылаетесь.

...
while [ true ]; do
    if [ -z $(cat /tmp/pause) ]; then
        STOPWATCH=$(TZ=UTC datef $DATE_INPUT $DATE_FORMAT | ( [[ "$NANOS_SUPPORTED" ]] && sed 's/.\{7\}$//' || cat ) )
        printf "\r\e%s" $STOPWATCH
        sleep 0.03
    fi
done

Итак, что вам нужно сделать сейчас - это сценарий оболочки, который ожидает символ "p" от stdin и пишет 1> / tmp /сделать паузу или очистить / tmp / pause, чтобы остановить или запустить секундомер.

что-то вроде:

while read char;
do 
   if [ $char == "p" ]; then
       if [ -z $(cat /tmp/pause) ];then
           echo 1 > /tmp/pause
       else
           echo > /tmp/pause
       fi
       char=0 
   fi
done < /dev/stdin
...