Нажмите любую клавишу, чтобы приостановить сценарий оболочки, нажмите еще раз, чтобы продолжить


11

Я написал сценарий оболочки для тестирования API, который копирует файлы и отображает их прогресс после каждого.

Между каждой копией существует двухсекундный сон, поэтому я хотел бы добавить возможность нажатия любой клавиши, чтобы приостановить выполнение сценария, чтобы провести более глубокое тестирование. Затем нажмите любую клавишу для возобновления.

Как я могу добавить это как можно меньше строк?

Ответы:


12

Вам не нужно добавлять что-то в ваш скрипт. Оболочка допускает такую ​​функциональность.

  • Запустите ваш скрипт в терминале.
  • Пока работает и блокирует использование терминала ctrl- z. Терминал снова освобождается, и вы видите сообщение о том, что процесс остановлен. (Сейчас он в состоянии porcess T, остановлен)
  • Теперь делай что хочешь. Вы также можете запускать другие процессы / скрипты и останавливать их с помощью ctrl- z.
  • Введите jobsв терминал или список всех остановленных заданий.
  • Чтобы продолжить выполнение сценария, введите fg(передний план). Он возобновляет работу обратно в группу процессов переднего плана, и задания продолжают выполняться.

Смотрите пример:

root@host:~$ sleep 10 # sleep for 10 seconds
^Z
[1]+  Stopped                 sleep 10
root@host:~$ jobs # list all stopped jobs
[1]+  Stopped                 sleep 10
root@host:~$ fg # continue the job
sleep 10
root@host:~$ # job has finished

Как вы сказали, если я запустлюсь sleep 10; notify-send helloи нажму CTRL + Z, чтобы остановиться, notify-send helloначните выполнение. если вторая команда выполняется, почему первый процесс останавливается? после этого, если набрать, fgя не вижу ничего, что происходит, что очевидно, поскольку вторая команда уже выполнена
Эдвард Торвальдс,

@edwardtorvalds, потому что две команды являются отдельными. В сценарии они должны быть в подоболочке. Напишите их в простом сценарии и выполните сценарий. Затем нажмите Ctrl-Z, чтобы остановить, и вы увидите, что вторая команда не выполняется, пока не завершится первая. Письмо cmd; cmd; cmd;похоже на письмо cmd <newline> cmd <newline> .... В качестве альтернативы сценарию, который вы можете написать ( cmd; cmd; cmd; ), он будет вести себя как сценарий, как основа подоболочки, сгенерированной(
chaos

я тоже попробовал sleep 10. когда я нажимаю CTRL + Z через 3 секунды и возобновляюсь через несколько секунд, и замечаю, что команда сна умерла менее чем за 7 секунд. что противоположно тому, что вы сказали, поскольку команда nevers останавливается, она просто работает в фоновом режиме.
Эдвард Торвальдс

@edwardtorvalds Я тоже это заметил ... Не имеет смысла. Я straced в sleepкоманду и узнал, что системный вызов используется nanosleep(). Кажется, это определенное поведение системного вызова nanosleep. restart_syscall()перезапускает прерванный системный вызов с аргументом времени, который соответствующим образом настроен для учета времени, которое уже прошло (включая время, когда процесс был остановлен сигналом). Прочтите эту man- страницу
хаос

Несколько замечаний для завершения ответа @chaos (не стесняйтесь включать их): когда вы нажимаете ctrl-Z, задание приостанавливается («останавливается»), поэтому в данный момент оно не выполняется, ожидая решения продолжить его. на переднем плане (например:) fg %1или на заднем плане (например:) bg %1. (если задания выдают только 1 номер, то есть только 1 приостановленный процесс, как показано в примере с хаосом: только [1]+ stopped sleep 10, вы можете опустить %nдеталь. Если есть несколько фоновых процессов (запущенных или остановленных), вам нужно назначить тот, который вы хотите с: %n(например, fg %2 чтобы% 2 возобновилось на переднем плане))
Оливье Дюлак

6

Если вы хотите просто приостановить выполнение сценария, оставаясь внутри сценария, вы можете использовать чтение вместо сна.

Ты можешь использовать

read -tустановить тайм-аут чтения
read -nдля чтения одного символа (фактически просто нажмите любую клавишу), чтобы продолжить сценарий

Поскольку вы не предоставили никакого кода, ниже приведен пример того, как его можно использовать.
Если нажать q, то read -n1сценарий не будет продолжаться до тех пор, пока не будет нажата клавиша.
Когда клавиша нажата, проверка сбрасывается, и сценарий продолжает цикл как обычно.

while [[ true ]]; do
    read -t2 -n1 check
    if [[ $check == "q" ]];then
        echo "pressed"
        read -n1
        check=""
    else
        echo "not pressed"
    fi
echo "Doing Something"
done

Вы также можете добавить stty -echoв начало раздела и stty echoв конец, чтобы не допустить путаницы при наборе текста


@mikeserv Я не думаю, что оператору важно, что читается, они просто хотят приостановить и возобновить сценарий, что вы подразумеваете под сохранением настроек терминала, я только изменяю один, так что это кажется немного излишним.

1
@mikeserv, да, я просто предполагал, что все stdin будет исходить от пользователя.

1

С ddего помощью можно надежно прочитать один байт из файла. С помощью sttyвы можете установить minколичество байтов, чтобы квалифицировать чтение терминала и timeвыход в десятых долях секунды. Объедините эти два, и вы можете обойтись без них sleep, я думаю, и просто дайте таймауту чтения терминала сделать работу за вас:

s=$(stty -g </dev/tty)
(while stty raw -echo isig time 20 min 0;test -z "$(
dd bs=1 count=1 2>/dev/null; stty "$s")" || (exec sh)
do echo "$SECONDS:" do your stuff here maybe                             
   echo  no sleep necessary, I think                                                          
   [ "$((i+=1))" -gt 10 ] && exit                                                             
done       
) </dev/tty

Это небольшой пример whileцикла, который я смоделировал для вас, чтобы попробовать. Каждые две секунды ddистекает время попытки чтения stdin- перенаправлено с /dev/tty- и whileциклы цикла. Это или dd не время ожидания, потому что вы нажимаете клавишу - в этом случае вызывается интерактивная оболочка.

Вот тестовый прогон - числа, напечатанные в заголовке каждой строки, являются значением переменной оболочки $SECONDS :

273315: do your stuff here maybe
no sleep necessary, I think
273317: do your stuff here maybe
no sleep necessary, I think
273319: do your stuff here maybe
no sleep necessary, I think
273321: do your stuff here maybe
no sleep necessary, I think
sh-4.3$ : if you press a key you get an interactive shell
sh-4.3$ : this example loop quits after ten iterations
sh-4.3$ : or if this shell exits with a non-zero exit status
sh-4.3$ : and speaking of which, to do so you just...
sh-4.3$ exit
exit
273385: do your stuff here maybe
no sleep necessary, I think
273387: do your stuff here maybe
no sleep necessary, I think
273389: do your stuff here maybe
no sleep necessary, I think
273391: do your stuff here maybe
no sleep necessary, I think
273393: do your stuff here maybe
no sleep necessary, I think
273395: do your stuff here maybe
no sleep necessary, I think
273397: do your stuff here maybe
no sleep necessary, I think

Разве вы не должны использовать stty saneпосле изменения настроек STTY, я могу ошибаться, но не похоже, что вы их сбросили где-нибудь?

@Jidder - нет, я сохраняю состояние терминала в верхней части скрипта с помощью s=$(stty -g </dev/tty). Сразу после звонка ddя потом восстановил с помощью stty "$s". Состояние терминала не заботится о подоболочках, поэтому эти настройки остаются неизменными независимо от родительской оболочки. stty saneэто не обязательно то, что вы хотите сделать - лучше восстановить состояние так, как вы его нашли, чем предполагать, что состояние было saneв тот момент. Если бы я не восстановил это, эти echoбыли бы повсюду. Отчасти это понятно, поэтому я пришел так поздно - ваш ответ не был здесь, когда я начал тестирование.
mikeserv
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.