Как остановить скрипт Bash с помощью пробела?

Как остановить скрипт Bash с помощью пробела?

Я работаю над секундомером для кубика Рубика, написанным на Bash, и мне бы хотелось останавливать его нажатием клавиши пробела, поскольку нажатие клавиши Ctrl«+» Cневыполнимо, когда нужно остановить его как можно быстрее.

Так есть ли способ остановить программу, просто нажав пробел?

Я посмотрел на команду, killкоторую не мог понять.

Часть кода, отвечающая за секундомер, приведена ниже:

TMP0=$(date +%s%N)
while true; do
    TMP1=$(date +%s%N)
    DTMP=$(($TMP1-$TMP0))
    printf "\r$(($DTMP/1000000000)).${DTMP:(-9):2}"
done

решение1

Это ваш терминал отправляет SIGINT в группу процессов переднего плана, когда вы нажимаете Ctrl+ c. Вы можете настроить его так, чтобы он делал это для любого символа, но вы хотите восстановить старые настройки при выходе из скрипта.

#!/bin/bash

settings="$(stty -g)"
trap 'stty "$settings"' EXIT
stty intr ' '

TMP0=$(date +%s%N)
while true; do
    TMP1=$(date +%s%N)
    DTMP=$(($TMP1-$TMP0))
    printf '\r%s' "$(($DTMP/1000000000)).${DTMP:(-9):2}"
done

settings="$(stty -g)"сохраняет старые настройки; stty intr ' 'заставляет терминал реагировать на Spaceвместо Ctrl+ c; trap 'stty "$settings"' EXITотвечает за восстановление старых настроек при выходе из скрипта.

Примечания:

  • В коде ловушки stty $settingsлучше, чем stty "$settings". Это исключение из "всегда цитируйте" правило. Кавычки предотвращают разбиение слов и генерацию имен файлов (подстановку), но некоторые реализации sttyмогут потребовать разбиения слов, для них переменная не должна заключаться в кавычки. Чтобы избежать вредных побочных эффектов от генерации имен файлов,Спецификациятребуется stty -gсгенерировать строку, которая не активирует эту функцию.

    Редактировать:это был дефект в спецификации POSIX. Приведенный выше код был исправлен.

  • В случае, если что-то пойдет не так и вы окажетесь в интерактивной оболочке, где Spaceвсе еще генерируется SIGINT, вам нужно вызвать stty intr ^Cвручную. В команде есть пробелы, но имейте в виду, что вы все равно можете ввести буквальный символ пробела, нажав Ctrl+ v Space.

  • Я использовал его, printf '\r%s' …потому что считаю, что статический формат и динамические данные лучше соответствуют «философии», printfчем динамический формат, который использовали вы.

" Spaceвместо Ctrl+ c" означает, что когда Spaceстановится особенным, Ctrl+ cперестает быть особенным. Вы можете назвать это недостатком, потому чтопользователи будут ожидать , что Ctrl+ cостанется особенным. Однако сделать их одновременно особенными не так-то просто, я думаю, это невозможно сделать путем настройки терминала.

Эта альтернативная версия останавливается практически на любой клавише, в то время как Ctrl+ cработает как обычно:

#!/bin/bash

while read -r -t 0.001; do :; done    # dump the buffer
TMP0=$(date +%s%N)
until read -r -n 1 -t 0.001; do
    TMP1=$(date +%s%N)
    DTMP=$(($TMP1-$TMP0))
    printf '\r%s' "$(($DTMP/1000000000)).${DTMP:(-9):2}"
done
echo

Чтобы он реагировал Spaceтолько на то, что вам нужно проверить, что было прочитано:


until read -r -n 1 -t 0.001 && [ "$REPLY" = ' ' ]; do

Обратите внимание, что механизм Spaceостановки скрипта теперь сильно отличается от того, как работает Ctrl+ c.

решение2

Если вам не нужен секундомер, а вы просто хотите узнать, сколько времени в итоге потребовалось, вы можете использовать:

time read -r -n 1

это даст вам вывод вроде:

time read -r -n 1

real    1m30.909s
user    0m0.000s
sys     0m0.000s

и останавливаться практически при любом нажатии клавиши (подобно тому, как Камил использует read)

или если вам нужна только часть времени:

{ time read -r -n 1; } 2>&1 | grep real | awk '{ print $2 }'

любезно предоставленоричи

Связанный контент