Как я могу разбудить спящий сценарий bash?

27

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


В качестве примера, скажем, у вас есть этот скрипт:

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

Через 30 минут вы обнаружите, что вам нужно остановить сценарий, то есть вы хотели бы написать sleep 30mвместо этого.

Вы не хотите ни звонить, kill PIDни нажимать Ctrl+ C, так как тогда последняя команда не будет выполнена, и вы останетесь уставшим.

Есть ли способ разбудить процесс sleepили, возможно, использовать другую команду, которая поддерживает пробуждение? Решения как фоновых, так и передних процессов приветствуются.

Bittenus
источник
13
Кричи на это очень громко.
Дверная ручка
2
@ Doorknob gawking действительно не работает. В прошлый раз, когда у меня был sleepпроцесс размышления, я pushdподнялся с кровати.
Ималлетт
В вашем сценарии отсутствует #!строка. И это важно, потому что ответ на ваш вопрос зависит от того, есть ли -eв #!очереди.
Касперд
1
@kasperd Готово. Из любопытства: какое влияние имеет флаг -e?
Биттенус
2
По умолчанию скрипт будет продолжен после ошибки. Если вы используете #!/bin/bash -e, сценарий остановится после ошибки. Простое уничтожение команды sleep будет рассматриваться как ошибка bash. Это означает, что -eнет достаточно простого ответа на ваш вопрос. Если -eего использовать, то это становится намного сложнее, потому что вам нужно будет остановить процесс сна, не убивая его.
Касперд

Ответы:

47

Когда скрипт Bash запускается sleep, вот как это pstreeможет выглядеть:

bash(10102)───sleep(8506)

Оба имеют идентификаторы процессов (PID) даже при запуске в качестве сценария. Если бы мы хотели прервать сон, мы бы отправили kill 8506и сеанс Bash возобновился бы ... Проблема в сценариях, мы не знаем PID sleepкоманды, и нет человека, который бы смотрел на процесс дерево.

Мы можем получить PID сеанса Bash через $$магическую переменную. Если мы можем сохранить это где-то, мы можем затем нацелить экземпляры sleep, которые работают под этим PID. Вот что я вставил в сценарий:

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

# go to sleep for a long time
sleep 1000

И тогда мы можем сказать pkillядерным sleepэкземплярам, ​​работающим под этим PID:

pkill -P $(<myscript.pid) sleep

Опять же, это ограничивается только sleepпроцессами, запущенными непосредственно в этом сеансе Bash. До тех пор, пока PID был зарегистрирован правильно, это делает его намного безопаснее, чем killall sleepили pkill sleep, что может привести к обесточиванию любого sleep процесса в системе (разрешения разрешают).

Мы можем доказать , что теория со следующим примером , в котором есть три отдельных Баш сессий, два хода sleep. Только потому, что мы указываем PID верхнего левого сеанса bash, sleepуничтожается только его .

введите описание изображения здесь


Альтернативный подход состоит в том, чтобы нажать sleepна задний план, сохранить его PID и затем вернуть его на передний план. В сценарии:

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

И убить это

kill $(<myscript.sleep.pid)
Оли
источник
5

Вы можете написать свой сценарий для обработки («перехвата») других сигналов от kill и т. Д., Чтобы при необходимости можно было изменить поведение сценариев. Смотри, человек Баш:

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.
afbach
источник
4

Вы можете просто убить сон, который будет продолжаться до следующей строки скрипта:

pkill sleep

Обратите внимание, что это убило бы любой спящий процесс, работающий в вашей системе, а не только в вашем скрипте.

animaletdesequia
источник
1

У меня есть скрипт bash, запущенный при cronзагрузке. Сценарий просыпается каждую минуту и ​​устанавливает яркость дисплея ноутбука в зависимости от восхода и захода солнца, полученных из Интернета. Настраиваемая пользователем фаза перехода между полной яркостью и полной яркостью требует увеличения и уменьшения значений на 3, 4, 5 или что-либо другое, рассчитанное каждую минуту.

Оли кратко затронул pstreeв своем ответе, но отклонил его, потому что это убило бы все sleepслучаи. Этого можно избежать, сузив поиск с помощью параметров pstree.

Используя pstree -hмы видим всю иерархию:

$ 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

Как видите, типичный логин в Ubuntu содержит много PID (идентификаторов процессов).

Мы можем сузить его до нашего запущенного скрипта, используя:

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

Мы видим:

  • cron запустил оболочку (идентификатор процесса 1308 и идентификатор сеанса 1308)
  • Оболочка вызывает нашу программу, запущенную с идентификатором 1321 процесса и идентификатором 1308 сеанса (соответствует оболочке)
  • Наша программа вызывает sleepпроцесс с идентификатором 26552 и снова сессионный идентификатор 1308

На данный момент мы можем использовать, pkill -s 1308и это убьет весь сеанс, который включает в себя оболочку, нашу программу display-auto-brightnessи sleepкоманду. Вместо этого мы будем использовать kill 26552только команду «sleep», которая заставит нашу программу проснуться и отрегулировать яркость.

Набрав это вручную в терминале, вы увидите:

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

Следующий шаг - сделать это, когда ноутбук выйдет из режима ожидания. Например, когда крышка была закрыта, она была полностью темной, а яркость экрана была установлена ​​на «300». Когда крышка открыта, это дневной свет, и яркость должна быть установлена ​​на «2000». Конечно, программа просыпается сама по себе через 1–59 секунд, но более удобно мгновенно устанавливать яркость.

Я опубликую код приостановки / возобновления после того, как он будет написан. Надеюсь, в эти выходные.

WinEunuuchs2Unix
источник