Как продолжить скрипт после перезагрузки машины?

18

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

sudo reboot

Когда машина возвращается, есть еще работа, которую должен выполнить этот скрипт. Как мне что-то настроить, чтобы продолжить работу в этом скрипте?

Я предполагаю, что есть место, где я могу написать сценарий оболочки, чтобы он выполнялся при следующей перезагрузке. Где такое место? Я вижу, что у cron есть директива @reboot. Я также знаю, что такие службы, как Apache, запускаются при загрузке при помощи upstart. Подойдут ли какие-либо из этих механизмов? Если так, как это будет вызвано?

Этот скрипт нужно запускать только один раз, а не каждую перезагрузку. Так что он должен будет пойти куда-нибудь, что просто запустится при следующей перезагрузке, или сможет удалить себя после запуска.

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

Моя конкретная версия - Ubuntu Linux 14.04. Исходный скрипт запускается в командной строке системным администратором (в отличие от запуска из cron).

Стивен Остермиллер
источник
Перезагрузка в скрипте должна использоваться только в том случае, если вы НЕ МОЖЕТЕ избежать этого. Например, установка нового ядра. Я уверен, что вы можете сделать свою работу без перезагрузки. Можете ли вы указать, зачем вам нужна перезагрузка?
хаос
1
Этот скрипт устанавливает новое ядро ​​(или, скорее, вызывает apt upgrade, которое может это сделать). Кроме того, он также проверяет, нужна ли перезагрузка перед перезагрузкой.
Стивен Остермиллер
«Перезагрузка в скрипте должна использоваться только в том случае, если вы НЕ МОЖЕТЕ избежать этого». - @chaos Почему?
Джон Ред

Ответы:

16

В системе единственное, что действительно является постоянным, - это файл. Это в значительной степени то, что вы должны использовать. Вот решение с использованием сценария init.d.

Давайте рассмотрим следующий (простой) скрипт /etc/init.d/myupdate:

#! /bin/sh

### BEGIN INIT INFO
# Provides:          myupdate
### END INIT INFO

PATH=/sbin:/bin:/usr/sbin:/usr/bin

case "$1" in
    start)
        /path/to/update/script
        ;;
    stop|restart|reload)
        ;;
esac

Если вы активируете его с помощью update-rc.d myupdate defaults, startдействие будет выполнено при загрузке. Теперь, когда ваш скрипт обновления требует перезагрузки:

touch /var/run/rebooting-for-updates
sudo reboot

С помощью этого решения вы можете разделить ваш скрипт обновления на две части:

before_reboot(){
    # Do stuff
}

after_reboot(){
    # Do stuff
}

if [ -f /var/run/rebooting-for-updates ]; then
    after_reboot
    rm /var/run/rebooting-for-updates
    update-rc.d myupdate remove
else
    before_reboot
    touch /var/run/rebooting-for-updates
    update-rc.d myupdate defaults
    sudo reboot
fi

Он выполнит before_rebootраздел кода, создаст файл /var/runи перезагрузится. При загрузке сценарий будет вызван снова, но поскольку файл существует, after_rebootбудет вызываться вместо before_reboot.

Обратите внимание, что update-rc.d требуются права суперпользователя.

Без использования файла (из комментария Стивена Остермиллера ):

Если вы знакомы с getoptsутилитой, вы можете использовать опции вместо файлов. В скрипте инициализации вызовите скрипт с:

/path/to/update/script -r

И в вашем скрипте проверьте параметры вместо файлов. Вызовите ваш скрипт один раз без опции, и init.d вызовет его снова при загрузке, на этот раз с -r.

# Set AFTER_REBOOT according to options (-r).

if [ "x$AFTER_REBOOT" = "xyes" ]; then
    # After reboot
else
    # Before reboot
fi

Вы найдете больше информации об обработке опций здесь (только для коротких опций) . Я также отредактировал свой сценарий с вызовами, чтобы update-rc.dсохранить это разовую работу (из другого комментария).

Джон У. Смит
источник
2
Это может быть проще позвонить /path/to/update/script --after-rebootиз , /etc/init.d/myupdateа не полагаться на присутствие /var/run/rebooting-for-updates. Тогда он будет иметь разные аргументы при запуске напрямую по сравнению с вызовом при загрузке.
Стивен Остермиллер
Хороший, не думал о вариантах. Разрешите мне отредактировать;)
Джон В. У. Смит
1
Кроме того, поскольку это одноразовая работа, я бы, вероятно, хотел бы добавить update-rc.d myupdate defaultsи update-rc.d myupdate removeв сам скрипт, а также написание и удаление, /etc/init.d/myupdateчтобы не оставлять файлы без присмотра.
Стивен Остермиллер
Я реализовал это, и это работает хорошо. Единственное, что я добавлю, это то, что моей системе на основе Debian требуются дополнительные элементы в INIT INFOразделе: wiki.debian.org/LSBInitScripts
Стивен Остермиллер,
Я действительно хотел, чтобы все было просто;) Написание правильного init.d занимает немного времени, но я рад, что вы пошли за дополнительной информацией: эти скрипты могут стать довольно удобными.
Джон У. С. Смит,