Como posso ativar um script bash para dormir?


27

É possível ativar um processo que está em pausa usando o sleepcomando?


Como exemplo, digamos que você tenha este script:

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

Após 30 minutos, você descobre que precisa que o script seja interrompido, ou seja, desejava ter escrito sleep 30m.

Você não deseja ligar kill PIDou pressionar Ctrl+ C, pois o último comando não será executado e você permanecerá cansado.

Existe uma maneira de ativar o processo sleepou talvez usar outro comando que suporte a ativação? Soluções para processos em segundo plano e em primeiro plano são bem-vindas.


13
Grite muito alto.
Maçaneta da porta

2
@Doorknob gawking realmente não funciona. A última vez que tive um sleepprocesso, pushdtirei da cama.
precisa saber é o seguinte

Seu script está faltando uma #!linha. E isso importa, porque a resposta à sua pergunta depende da existência de alguma -ena #!fila.
kasperd

1
@kasperd Concluído. Por curiosidade: que influência a bandeira -e tem?
Bittenus

2
Por padrão, um script continuará após um erro. Se você usar #!/bin/bash -e, o script será interrompido após um erro. Simplesmente matar o comando sleep será tratado como um erro pelo bash. Isso significa que sem -euma resposta bastante simples para sua pergunta. Se -efoi usado, torna-se muito mais difícil, porque você precisaria interromper o processo de sono sem matá-lo.
kasperd

Respostas:


47

Quando um script Bash está executando um sleep, aqui está a pstreeaparência:

bash(10102)───sleep(8506)

Ambos têm IDs de processo (PIDs), mesmo quando executados como um script. Se quiséssemos interromper o sono, enviaríamos kill 8506e a sessão do Bash seria retomada ... O problema está em um ambiente com script que não conhecemos o PID do sleepcomando e não há um humano para analisar o processo árvore.

Podemos obter o PID da sessão do Bash através da $$variável mágica. Se pudermos armazenar isso em algum lugar, podemos direcionar instâncias sleepque estão sendo executadas sob esse PID. Aqui está o que eu colocaria no script:

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

# go to sleep for a long time
sleep 1000

E então podemos dizer pkillpara sleepinstâncias nucleares em execução sob esse PID:

pkill -P $(<myscript.pid) sleep

Novamente, isso está se limitando apenas aos sleepprocessos em execução diretamente nessa única sessão do Bash. Contanto que o PID tenha sido registrado corretamente, isso o torna muito mais seguro que killall sleepou pkill sleep, o que poderia causar um nulo em qualquersleep processo do sistema (permissões permitidas).

Podemos provar essa teoria com o exemplo a seguir, onde temos três sessões de bash separadas, duas em execução sleep. Somente porque estamos especificando o PID da sessão do bash do canto superior esquerdo, apenas ele sleepé eliminado.

insira a descrição da imagem aqui


Uma abordagem alternativa é colocar sleepem segundo plano, armazenar seu PID e devolvê-lo ao primeiro plano. No script:

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

E para matá-lo:

kill $(<myscript.sleep.pid)

5

Você pode escrever seu script para manipular ("interceptar") outros sinais de kill etc., para modificar o comportamento dos scripts conforme necessário. Veja 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

Você poderia simplesmente matar o sono, o que continuaria na próxima linha do script:

pkill sleep

Observe que isso mataria qualquer processo de suspensão em execução no seu sistema, não apenas no seu script.


1

Eu tenho um script bash adormecido iniciado cronna inicialização. O script acorda a cada minuto e define o brilho da tela do laptop com base no nascer e no pôr do sol obtidos na Internet. Uma fase de transição configurável pelo usuário entre brilho total e escurecimento total requer intensificação e redução de valores em 3, 4, 5 ou o que for calculado a cada minuto.

Oli tocou brevemente pstreeem sua resposta, mas a rejeitou, porque mataria todas as sleepinstâncias. Isso pode ser evitado restringindo a pesquisa usando as opções pstree.

Usando pstree -hvemos toda a hierarquia:

$ 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

Como você pode ver, um login típico do Ubuntu contém muitos PIDs (Process IDs).

Podemos reduzi-lo ao nosso script em execução usando:

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

Nós vemos:

  • cron iniciou um shell (ID do processo 1308 e ID da sessão 1308)
  • O shell chama nosso programa em execução sob o ID do processo 1321 e o ID da sessão 1308 (correspondendo ao shell)
  • Nosso programa chama sleepsob o ID do processo 26552 e novamente o ID da sessão 1308

Nesse ponto, podemos usar pkill -s 1308e isso mataria toda a sessão, que inclui o shell, nosso programa display-auto-brightnesse o sleepcomando. Em vez disso, usaremos kill 26552apenas para matar o comando de suspensão, forçando nosso programa a ativar e ajustar o brilho.

Digitando isso manualmente no terminal, você vê:

───────────────────────────────────────────────────────────────────────────────
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:~$ 

O próximo passo é fazer isso quando o laptop acordar da suspensão. Por exemplo, quando a tampa foi fechada, estava totalmente escuro e o brilho da tela foi definido como "300". Quando a tampa é aberta, a luz do dia e o brilho precisam ser ajustados para "2000". É claro que o programa acordaria sozinho em 1 a 59 segundos, mas é mais confortável que o brilho seja definido instantaneamente.

Vou postar o código de suspensão / currículo depois que ele for escrito. Espero que este fim de semana.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.