Naciśnij dowolny klawisz, aby wstrzymać skrypt powłoki, naciśnij ponownie, aby wznowić

11

Napisałem skrypt powłoki do testowania interfejsu API, który kopiuje pliki i po każdym powtarza jego postęp.

Pomiędzy każdą kopią jest dwusekundowy sen, dlatego chciałbym dodać możliwość naciśnięcia dowolnego klawisza, aby wstrzymać skrypt i umożliwić głębsze testowanie. Następnie naciśnij dowolny klawisz, aby wznowić.

Jak mogę to dodać w jak najmniejszej liczbie wierszy?

blarg
źródło

Odpowiedzi:

12

Nie musisz dodawać czegoś do skryptu. Powłoka umożliwia taką funkcjonalność.

  • Uruchom skrypt w terminalu.
  • Podczas gdy działa i blokuje użycie terminala ctrl- z. Terminal zostanie ponownie zwolniony i zobaczysz komunikat, że proces został zatrzymany. (Teraz jest w stanie porcess T, zatrzymany)
  • Teraz rób co chcesz. Możesz także uruchomić inne procesy / skrypty i zatrzymać je za pomocą ctrl- z.
  • Wpisz jobsterminal lub wyświetl listę wszystkich zatrzymanych zadań.
  • Aby kontynuować skrypt, wpisz fg(pierwszy plan). Wznawia zadanie z powrotem do grupy procesów pierwszego planu i zadania są kontynuowane.

Zobacz przykład:

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
chaos
źródło
tak jak powiedziałeś, jeśli uruchomię sleep 10; notify-send helloi naciśnij klawisze CTRL + Z, aby zatrzymać, wykonaj polecenie notify-send hello. jeśli wykonywane jest drugie polecenie, dlaczego pierwszy proces zostaje zatrzymany? potem, jeśli typ fgi nie mogę zobaczyć, co się dzieje, co jest oczywiste, ponieważ drugie polecenie jest już wykonane
Edward Torvalds
@edwardtorvalds, ponieważ dwa polecenia są osobne. W skrypcie mogą być w podpowłoce. Napisz je prostym skryptem i uruchom skrypt. Następnie ctrl-z, aby zatrzymać, a zobaczysz, że drugie polecenie nie jest wykonywane, dopóki pierwsze nie zakończy się. Pisanie cmd; cmd; cmd;jest jak pisanie cmd <newline> cmd <newline> .... Alternatywnie do skryptu, który możesz napisać ( cmd; cmd; cmd; ), działałby on jak skrypt, ponieważ wygenerowano podpowłokę(
chaos
też próbowałem sleep 10. kiedy naciskam CTRL + Z po 3 sekundach i wznawiam po kilku sekundach i zauważyłem, że polecenie uśpienia umarło w czasie krótszym niż 7 sekund. co jest przeciwieństwem tego, co powiedziałeś, ponieważ polecenie nevers zostaje zatrzymane, po prostu działa w tle.
Edward Torvalds
@edwardtorvalds Zauważyłem też, że ... To nie ma sensu. I straced sleeppolecenia i okazało się, że wywołanie system wykorzystywany jest nanosleep(). Wydaje się, że jest to określone zachowanie nanosleepwywołania systemowego. restart_syscall()ponownie uruchamia przerwane wywołanie systemowe z argumentem czasu, który jest odpowiednio dostosowywany, aby uwzględnić czas, który już upłynął (w tym czas, w którym proces został zatrzymany przez sygnał). Przeczytaj tę stronę: man7.org/linux/man-pages/man2/restart_syscall.2.html
chaos
Kilka notatek do uzupełnienia odpowiedzi @chaos (możesz je dołączyć): kiedy robi się ctrl-Z, zadanie jest zawieszone („zatrzymane”), więc w tej chwili nie jest uruchomione, czekając na decyzję o kontynuowaniu na pierwszym planie (ex:) fg %1lub w tle (ex:) bg %1. (jeśli zadania podają tylko 1 liczbę, tzn. tylko 1 zawieszony proces, jak pokazano w przykładzie chaosu: tylko [1]+ stopped sleep 10, możesz pominąć %nczęść. jeśli jest kilka procesów w tle (uruchomionych lub zatrzymanych), musisz wyznaczyć ten, który chcesz z: %n(np. fg %2 aby wznowić% 2 na pierwszym planie))
Olivier Dulac
6

Jeśli chcesz po prostu zatrzymać skrypt, pozostając w nim, możesz użyć odczytu zamiast snu.

Możesz użyć

read -tustawić limit czasu odczytu
read -ndla odczytu jednego znaku (w rzeczywistości wystarczy nacisnąć dowolny klawisz), aby kontynuować skrypt

Ponieważ nie podałeś żadnego kodu, poniżej znajduje się przykład jego użycia.
Naciśnięcie q read -n1uniemożliwia kontynuowanie skryptu do momentu naciśnięcia klawisza.
Po naciśnięciu klawisza sprawdzanie jest resetowane, a skrypt kontynuuje normalną pętlę.

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

Możesz także dodać stty -echona początku sekcji i stty echona końcu, aby zapobiec nieporządkowi pisania na ekranie


źródło
@ mikeserv Nie sądzę, że op obchodzi to, co jest czytane, po prostu chcą zatrzymać i wznowić skrypt, co masz na myśli również przez zapisanie ustawień terminala, zmieniam tylko jeden, więc wydaje się, że to trochę przesada.
1
@ mikeserv ahh racja, właśnie zakładałem, że wszystkie stdin będą pochodzić od użytkownika.
1

Dzięki ddniemu możesz niezawodnie odczytać pojedynczy bajt z pliku. Za pomocą sttymożna ustawić minliczbę bajtów, aby zakwalifikować terminal do odczytu i do timedziesiątych części sekundy. Po połączeniu tych dwóch elementów możesz to zrobić sleepcałkowicie, myślę, i pozwól, aby limit czasu odczytu terminala wykonał pracę za Ciebie:

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

To jest mała przykładowa whilepętla, którą przygotowałem, abyś mógł ją wypróbować. Co dwie sekundy ddkończy się próba odczytania stdin- przekierowanie z /dev/tty- i whilepętli pętli. To lub dd nie kończy się, ponieważ naciskasz klawisz - w takim przypadku wywoływana jest interaktywna powłoka.

Oto przebieg testowy - liczby wydrukowane na początku każdego wiersza są wartością zmiennej powłoki $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
mikeserv
źródło
Nie powinieneś używać stty sanepo zmianie ustawień stty, mogę się mylić, ale nie wygląda na to, że nigdzie je zresetowałeś?
@Jidder - nie Zapisuję stan terminala na górze skryptu za pomocą s=$(stty -g </dev/tty). Natychmiast po wywołaniu ddprzywracam go za pomocą stty "$s". Stan terminalu nie dba o podpowłoki, więc te ustawienia zostają zachowane niezależnie od powłoki nadrzędnej. stty saneniekoniecznie jest to, co chcesz zrobić - lepiej przywrócić stan do stanu, w którym go znalazłeś, niż założyć, że stan był sanew tym momencie. Gdybym tego nie przywrócił, te echobyłyby wszędzie. Zrozumienie tego jest częściowo powodem, dla którego przyjechałem tak późno - Twoja odpowiedź nie pojawiła się tutaj, kiedy zacząłem testować.
mikeserv