Come posso svegliare uno script bash addormentato?


27

È possibile riattivare un processo in pausa usando il sleepcomando?


Ad esempio, supponiamo che tu abbia questo script:

#!/bin/bash
echo "I am tired"
sleep 8h
echo "I am fresh :)"

Dopo 30 minuti scopri che hai bisogno che la sceneggiatura si fermi, cioè avresti voluto sleep 30minvece aver scritto .

Non vuoi né chiamare kill PIDné premere Ctrl+ C, da allora l'ultimo comando non viene eseguito e rimarrai stanco.

C'è un modo per riattivare il processo sleepo forse usare un altro comando che supporta il wakeup? Le soluzioni ai processi sia in background che in primo piano sono benvenute.


13
Urla molto forte.
Maniglia della porta,

2
@Doorknob gawking non funziona davvero. L'ultima volta che ho avuto un sleepprocesso ing, l'ho pushdpreso dal letto.
imallett,

Nel tuo script manca una #!riga. E questo è importante perché la risposta alla tua domanda dipende dal fatto che ce ne sia -enella #!linea.
Kasperd,

1
@kasperd Fatto. Per curiosità: che influenza ha la bandiera -e?
Bittenus,

2
Per impostazione predefinita, uno script continuerà dopo un errore. Se lo usi #!/bin/bash -e, lo script si interromperà dopo un errore. Semplicemente uccidere il comando sleep sarà trattato come un errore da bash. Ciò significa che senza -ec'è una risposta abbastanza semplice alla tua domanda. Se è -estato usato, diventa molto più difficile perché dovresti interrompere il processo di sonno senza ucciderlo.
Kasperd,

Risposte:


47

Quando uno script Bash esegue un sleep, ecco come pstreepotrebbe apparire:

bash(10102)───sleep(8506)

Entrambi hanno ID di processo (PID), anche quando eseguiti come script. Se volessimo interrompere il sonno, invieremmo kill 8506e la sessione di Bash riprenderebbe ... Il problema è in un ambiente con script che non conosciamo il PID del sleepcomando e non esiste un essere umano che guardi il processo albero.

Possiamo ottenere il PID della sessione di Bash attraverso la $$variabile magica. Se possiamo archiviarlo da qualche parte, possiamo quindi scegliere come target istanze sleepche sono in esecuzione sotto quel PID. Ecco cosa avrei inserito nella sceneggiatura:

# write the current session's PID to file
echo $$ >> myscript.pid

# go to sleep for a long time
sleep 1000

E quindi possiamo dire pkillalle sleepistanze di Nuke in esecuzione sotto quel PID:

pkill -P $(<myscript.pid) sleep

Ancora una volta, questo si limita ai soli sleepprocessi in esecuzione direttamente in quella sessione Bash. Fintanto che il PID è stato registrato correttamente, questo lo rende molto più sicuro di killall sleepo pkill sleep, il che potrebbe danneggiare qualsiasi sleep processo sul sistema (permessi permessi).

Possiamo provare questa teoria con il seguente esempio in cui abbiamo tre sessioni bash separate, due in esecuzione sleep. Solo perché stiamo specificando il PID della sessione bash in alto a sinistra, sleepviene ucciso solo il suo .

inserisci qui la descrizione dell'immagine


Un approccio alternativo consiste nello spingere sleepin background, memorizzare il suo PID e quindi riportarlo in primo piano. Nella sceneggiatura:

sleep 1000 &
echo $! > myscript.sleep.pid
fg

E per ucciderlo:

kill $(<myscript.sleep.pid)

5

Potresti scrivere il tuo script per gestire ("trap") altri segnali da kill ecc. In modo da poter modificare il comportamento degli script secondo necessità. Vedi man bash:

SIGNALS
   When  bash  is  interactive,  in the absence of any traps, it ignores SIGTERM (so that kill 0 does not
   kill an interactive shell), and SIGINT is caught and handled (so that the wait builtin  is  interrupt-
   ible).   In all cases, bash ignores SIGQUIT.  If job control is in effect, bash ignores SIGTTIN, SIGT-
   TOU, and SIGTSTP.

   Non-builtin commands run by bash have signal handlers set to the values inherited by  the  shell  from
   its  parent.   When  job  control is not in effect, asynchronous commands ignore SIGINT and SIGQUIT in
   addition to these inherited handlers.  Commands run as a result of  command  substitution  ignore  the
   keyboard-generated job control signals SIGTTIN, SIGTTOU, and SIGTSTP.

   The shell exits by default upon receipt of a SIGHUP.  Before exiting, an interactive shell resends the
   SIGHUP to all jobs, running or stopped.  Stopped jobs are sent SIGCONT to ensure that they receive the
   SIGHUP.   To  prevent the shell from sending the signal to a particular job, it should be removed from
   the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or  marked  to  not  receive
   SIGHUP using disown -h.

   If  the huponexit shell option has been set with shopt, bash sends a SIGHUP to all jobs when an inter-
   active login shell exits.

   If bash is waiting for a command to complete and receives a signal for which a trap has been set,  the
   trap  will not be executed until the command completes.  When bash is waiting for an asynchronous com-
   mand via the wait builtin, the reception of a signal for which a trap has been set will cause the wait
   builtin  to  return immediately with an exit status greater than 128, immediately after which the trap
   is executed.

4

Potresti semplicemente uccidere il sonno che continuerebbe alla riga successiva dello script:

pkill sleep

Si noti che ciò ucciderebbe qualsiasi processo di sospensione in esecuzione nel sistema, non solo nello script.


1

Ho avviato uno script bash dormiente cron. Lo script si sveglia ogni minuto e imposta la luminosità del display del laptop in base all'alba e al tramonto ottenuti da Internet. Una fase di transizione configurabile dall'utente tra la piena luminosità e la piena oscurità richiede un aumento e una riduzione dei valori di 3, 4, 5 o qualsiasi cosa venga calcolata ogni minuto.

Oli accennò brevemente alla pstreesua risposta, ma la respinse perché avrebbe ucciso tutti i sleepcasi. Questo può essere evitato restringendo la ricerca usando le opzioni pstree.

Usando pstree -hvediamo l'intera erirarchia:

$ pstree -h
systemd─┬─ModemManager─┬─{gdbus}
                      └─{gmain}
        ├─NetworkManager─┬─dhclient
                        ├─dnsmasq
                        ├─{gdbus}
                        └─{gmain}
        ├─accounts-daemon─┬─{gdbus}
                         └─{gmain}
        ├─acpid
        ├─agetty
        ├─atd
        ├─avahi-daemon───avahi-daemon
        ├─cgmanager
        ├─colord─┬─{gdbus}
                └─{gmain}
        ├─cron───cron───sh───display-auto-br───sleep
        ├─cups-browsed─┬─{gdbus}
                      └─{gmain}
        ├─dbus-daemon
        ├─fwupd─┬─3*[{GUsbEventThread}]
               ├─{fwupd}
               ├─{gdbus}
               └─{gmain}
        ├─gnome-keyring-d─┬─{gdbus}
                         ├─{gmain}
                         └─{timer}
        ├─irqbalance
        ├─lightdm─┬─Xorg───3*[{Xorg}]
                 ├─lightdm─┬─upstart─┬─at-spi-bus-laun─┬─dbus-daemon
                                                    ├─{dconf worker}
                                                    ├─{gdbus}
                                                    └─{gmain}
                                   ├─at-spi2-registr─┬─{gdbus}
                                                    └─{gmain}
                                   ├─bamfdaemon─┬─{dconf worker}
                                               ├─{gdbus}
                                               └─{gmain}
                                   ├─chrome─┬─2*[cat]
                                           ├─chrome─┬─chrome─┬─2*[chrome─┬─{Chrome_ChildIOT}]
                                                                      ├─5*[{CompositorTileW}]]
                                                                      ├─{Compositor}]
                                                                      ├─{GpuMemoryThread}]
                                                                      ├─{MemoryInfra}]
                                                                      ├─{Renderer::FILE}]
                                                                      ├─{TaskSchedulerRe}]
                                                                      └─{TaskSchedulerSe}]
                                                           ├─7*[chrome─┬─{Chrome_ChildIOT}]
                                                                      ├─5*[{CompositorTileW}]]
                                                                      ├─{Compositor}]
                                                                      ├─{GpuMemoryThread}]
                                                                      ├─{MemoryInfra}]
                                                                      ├─{Renderer::FILE}]
                                                                      ├─{ScriptStreamerT}]
                                                                      ├─{TaskSchedulerRe}]
                                                                      └─{TaskSchedulerSe}]
                                                           ├─chrome─┬─{Chrome_ChildIOT}
                                                                   ├─5*[{CompositorTileW}]
                                                                   ├─{Compositor}
                                                                   ├─{GpuMemoryThread}
                                                                   ├─{Media}
                                                                   ├─{MemoryInfra}
                                                                   ├─{Renderer::FILE}
                                                                   ├─{ScriptStreamerT}
                                                                   ├─{TaskSchedulerRe}
                                                                   └─{TaskSchedulerSe}
                                                           └─2*[chrome─┬─{Chrome_ChildIOT}]
                                                                       ├─5*[{CompositorTileW}]]
                                                                       ├─{Compositor}]
                                                                       ├─{GpuMemoryThread}]
                                                                       ├─{Renderer::FILE}]
                                                                       ├─{ScriptStreamerT}]
                                                                       ├─{TaskSchedulerRe}]
                                                                       └─{TaskSchedulerSe}]
                                                   └─nacl_helper
                                           ├─chrome─┬─chrome
                                                   ├─{Chrome_ChildIOT}
                                                   ├─{MemoryInfra}
                                                   ├─{TaskSchedulerSe}
                                                   └─{Watchdog}
                                           ├─{AudioThread}
                                           ├─{BrowserWatchdog}
                                           ├─{Chrome_CacheThr}
                                           ├─{Chrome_DBThread}
                                           ├─{Chrome_FileThre}
                                           ├─{Chrome_FileUser}
                                           ├─{Chrome_HistoryT}
                                           ├─{Chrome_IOThread}
                                           ├─{Chrome_ProcessL}
                                           ├─{Chrome_SyncThre}
                                           ├─{CompositorTileW}
                                           ├─{CrShutdownDetec}
                                           ├─{D-Bus thread}
                                           ├─{Geolocation}
                                           ├─{IndexedDB}
                                           ├─{LevelDBEnv}
                                           ├─{MemoryInfra}
                                           ├─{NetworkChangeNo}
                                           ├─{Networking Priv}
                                           ├─4*[{TaskSchedulerBa}]
                                           ├─6*[{TaskSchedulerFo}]
                                           ├─{TaskSchedulerSe}
                                           ├─{WorkerPool/3166}
                                           ├─{WorkerPool/5824}
                                           ├─{WorkerPool/5898}
                                           ├─{WorkerPool/6601}
                                           ├─{WorkerPool/6603}
                                           ├─{WorkerPool/7313}
                                           ├─{chrome}
                                           ├─{dconf worker}
                                           ├─{extension_crash}
                                           ├─{gdbus}
                                           ├─{gmain}
                                           ├─{gpu-process_cra}
                                           ├─{inotify_reader}
                                           ├─{renderer_crash_}
                                           ├─{sandbox_ipc_thr}
                                           └─{threaded-ml}
                                   ├─compiz─┬─{dconf worker}
                                           ├─{gdbus}
                                           ├─{gmain}
                                           └─8*[{pool}]
                                   ├─conky───6*[{conky}]
                                   ├─2*[dbus-daemon]

( .... many lines deleted to fit in 30k limit .... )

        ├─vnstatd
        ├─whoopsie─┬─{gdbus}
                  └─{gmain}
        └─wpa_supplicant

Come puoi vedere, un tipico login di Ubuntu contiene molti PID (Process ID).

Possiamo limitarlo al nostro script in esecuzione usando:

$ pstree -g -p | grep display-auto
  |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(26552,1308)

Vediamo:

  • cron avviato una shell (ID processo 1308 e ID sessione 1308)
  • La shell chiama il nostro programma in esecuzione con ID processo 1321 e ID sessione 1308 (corrispondente alla shell)
  • Il nostro programma chiama sleepcon ID processo 26552 e di nuovo ID sessione 1308

A questo punto possiamo usare pkill -s 1308e ucciderebbe l'intera sessione che include la shell, il nostro programma display-auto-brightnesse il sleepcomando. Invece useremo kill 26552per uccidere solo il comando sleep costringendo il nostro programma a svegliarsi e regolare la luminosità.

Digitando questo manualmente nel terminale si vede:

───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ pstree -g -p | grep display-auto
             |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(32362,1308)
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ sudo kill 32362
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ pstree -g -p | grep display-auto
             |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(1279,1308)
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ sudo kill 1279
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ pstree -g -p | grep display-auto
             |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(4440,1308)
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ 

Il prossimo passo è farlo quando il laptop si sveglia dalla sospensione. Ad esempio, quando il coperchio era chiuso, era completamente buio e la luminosità dello schermo era impostata su "300". Quando il coperchio è aperto, è la luce del giorno e la luminosità deve essere impostata su "2000". Ovviamente il programma si risveglierebbe da solo in 1-59 secondi, ma è più comodo impostare la luminosità all'istante.

Pubblicherò il codice di sospensione / ripresa dopo che è stato scritto. Spero che questo fine settimana.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.