Если это вас беспокоит, то вы можете легко использовать интерфейс xscreensaver-command -watch
для запуска ssh-add -D
, когда экран заблокирован. Посмотрите на странице man очень простой пример.
Более простым решением было бы проинформировать пользователя о необходимости нажать Ctrl-C
для выхода из цикла, что выдаст сигнал SIGINT
и завершит сценарий.
Если вы хотите сделать что-то еще перед завершением скрипта, вы можете перехватить сигнал:
cleanup() {
#...
exit 0
}
trap 'cleanup' INT
Кроме того, вы можете запустить одну из них в подоболочке, убедившись, что при выходе из одной из оболочек другая также уничтожается. Таким образом, вы можете заблокировать один из них для ввода, в то время как другой выполняет другие проверки.
#!/bin/bash
i=1
sp="/-\|"
no_config=true
echo "type \"continue\" to exit this while loop if you feel the conditions for continuing sucessfully have been met... "
(
while $no_config
do
printf "\b${sp:i++%${#sp}:1}"
[[ ! $(pidof SupremeCommande) && -f ~/My\ Documents/newfile ]] && no_config=false
sleep 1
done
kill $$
) &
child_pid=$!
while $no_config
do
read -r typed_continue
[[ "$typed_continue" = "continue" ]] && no_config=false
sleep 1
done
kill $child_pid
К сожалению, Bash плохо подходит для таких элементов управления.
Однако есть несколько способов получить что-то работоспособное.
Вот некоторые из них, от самых простых до самых сложных:
Нажмите Ctrl+C для выхода
Вы можете установить trap
для Ctrl+C (, обрабатываемого путем перехвата сигнала INT ), чтобы он установил значение no_config
в false
, чтобы ваш цикл while
завершался при нажатии Ctrl+ С:
i=1
sp='/-\|'
no_config=true
echo "type Ctrl+C to exit this while loop"
echo "if you feel the conditions for continuing successfully have been met... ";
trap 'no_config=false' INT
while $no_config; do
printf "\b${sp:i++%${#sp}:1}"
[[ ! $(pidof SupremeCommande) && -f ~/My\ Documents/newfile ]] && no_config=false
sleep 1
done
trap 'trap - INT; kill -INT $$' INT
echo "do more stuff"
(Если вы запускаете приведенный выше код из интерактивной оболочки , не забудьте окружить весь код начальным (
и конечным )
, чтобы ваша оболочка не была загрязнена кодом. делает.)
Обратите внимание, что цикл while
будет фактически прерван только тогда, когда все команды внутри цикла будут завершены, потому что тест на $no_config
происходит только на while
. Вы можете или не хотите этого поведения в зависимости от того, что вы делаете внутри цикла. В вашем примере единственной истинной «медленной» операцией является явное sleep 1
, поэтому резкое прерывание не требуется, но если вы хотите прервать цикл, не имеет значения --, что тогда самое простое дополнение заключается в том, что с помощью одного вспомогательного -снаряда можно убить в целом. Вот так:
trap 'kill $!' INT
(
i=1
sp='/-\|'
no_config=true
echo "type Ctrl+C to exit this while loop"
echo "if you feel the conditions for continuing successfully have been met... ";
while $no_config; do
printf "\b${sp:i++%${#sp}:1}"
[[ ! $(pidof SupremeCommande) && -f ~/My\ Documents/newfile ]] && no_config=false
sleep 1
done
) &
wait
trap 'trap - INT; kill -INT $$' INT
echo "do more stuff"
Здесь мы устанавливаем trap
для INT (Ctrl+C ), что убивает вспомогательную оболочку -, так что wait
переходит к части «дополнительные действия».
Однако обратите внимание, что при таком способе переменные, установленные в цикле, не распространяются на часть «дополнительные действия». Чтобы обойти это, вам потребуются некоторые вспомогательные средства связи, такие как временный файл или именованный -FIFO.
Введите 'q' для выхода
Альтернативой вышеизложенному, которая позволит вам использовать любой символ для выхода (, а также оставить Ctrl+C в его обычной работе ), может быть встраивание неблокирующего -read
(, доступного в Bash. v4+ )внутри цикла. Это также требует некоторых вспомогательных приготовлений для настройки терминала.Все может быть так:
term_settings="$(stty -g)"
trap 'stty "${term_settings}"' EXIT
i=1
sp='/-\|'
no_config=true
echo "type exactly \"q\" to exit this while loop"
echo "if you feel the conditions for continuing successfully have been met... ";
stty -icanon -echo
while $no_config; do
while read -t 0 && read -rN 1 ; do [ "${REPLY}" = q ] && break 2 || true; done
printf "\b${sp:i++%${#sp}:1}"
[[ ! $(pidof SupremeCommande) && -f ~/My\ Documents/newfile ]] && no_config=false
sleep 1
done
stty "${term_settings}"
echo "do more stuff"
Здесь мы сначала сохраняем текущие настройки терминала, чтобы восстановить их позже и при ВЫХОДЕ, затем отключаем отображение набираемого символа(-echo
)и строки -, ориентированного на ввод с клавиатуры(-icanon
). В цикле while
мы используемread -t 0
(не-блокирующийread
)для проверки наличия типизированных символов, и в этом случае мы читаем их все один за другим (-N 1
), чтобы проверить, является ли какой-либо из них q
], чтобы выйти из цикла.
Это увеличивает вычислительную нагрузку из-за того, что read -t 0
выполняется на каждой итерации цикла while
. В вашем примере накладные расходы незначительны.
Если вы хотите внезапно прерываемый цикл с type q to quit
, необходим другой подход, и все становится намного сложнее, потому что вам приходится запускать прерываемую часть вашего кода в фоновом режиме, ожидая read
в коде переднего плана, и это также требует способа разблокировать read
, когда фоновый код завершается регулярно.
Чтобы получить это, требуется сильно расширить способности Баша, например:
read
. Это также означает, что будет невозможно передать переменные из цикла while
в часть «дополнительные действия», как мы уже говорили ранее (вспомогательная связь должна быть настроена специально ).
Пример может быть таким:
#!/bin/bash
term_settings="$(stty -g)"
(
trap 'stty "${term_settings}"' EXIT
_keyboard_waiter=$BASHPID
(
i=1
sp='/-\|'
no_config=true
echo "type exactly \"q\" to exit this while loop"
echo "if you feel the conditions for continuing successfully have been met... ";
while $no_config; do
printf "\b${sp:i++%${#sp}:1}"
[[ ! $(pidof SupremeCommande) && -f ~/My\ Documents/newfile ]] && no_config=false
sleep 1
done
kill -INT $_keyboard_waiter
) &
while read -rsN 1 && ! [ "${REPLY}" = q ] ; do :; done
{ kill $! && wait; } 2>/dev/null
)
echo "do more stuff"
Здесь имеем:
read
прерывается kill -INT
фоновой подпрограммой -для прерывания подпрограммы read
-. Это имитирует Ctrl+C для этой подпрограммы -, которая обрабатывается Bash read
, чтобы не отображать введенные символы (-s
), а также ожидать/принимать только один символ независимо от новой строки (-N 1
), плюс общий -r
, чтобы не интерпретировать обратную косую черту как escape-символ