Выполнить команду перед выключением

52

Я хочу выполнить простую команду как раз перед тем, как компьютер выключится (время не имеет значения).

Для запуска я могу использовать /etc/rc.local; Есть ли что-то подобное для выключения?

Обратите внимание, что я все еще хотел бы использовать встроенную кнопку выключения из меню; то есть я не хочу использовать собственный скрипт каждый раз, когда я выключаюсь через терминал - он должен быть автоматическим.

Примож Краль
источник

Ответы:

42

Linux Mint основан на Ubuntu, поэтому я предполагаю, что система уровня запуска, вероятно, такая же. В Ubuntu сценарии для разных уровней выполнения выполняются в соответствии с их присутствием в /etc/rc[0-6].dкаталогах. Уровень запуска 0 соответствует завершению работы, а 6 - перезагрузке.

Обычно сам скрипт хранится в нем /etc/init.d, а затем символические ссылки помещаются в каталоги, соответствующие требуемым уровням выполнения.

Так что в вашем случае напишите свой сценарий, сохраните его /etc/init.d/, затем создайте символическую ссылку в каждом из /etc/rc0.dи /etc/rc6.d(если вы хотите оба), указывающую на ваш сценарий.

Сценарии в каждом каталоге уровня выполнения будут выполняться в обычном порядке , поэтому, если для вас важен порядок в уровне выполнения, выберите имя символической ссылки соответственно.

ire_and_curses
источник
Я просто взглянул на файл скелета в init.d (точный kubuntu) и немного запугался. Я просто хочу добавить пару команд, которые отображают дату завершения работы в файл в / var / log. Могу ли я просто сделать это, или я должен иметь дело с некоторыми другими вещами в файле скелета?
Джо
2
@Joe - Вам не нужно больше всего этого, если только вы не хотите, чтобы ваш сценарий контролировался как стандартная служба. Вы ничего не сломаете простым эхо в вашем собственном файле журнала, так что попробуйте и посмотрите.
ire_and_curses
1
Вот простой пример скрипта init.d. Кроме того, сделать символические sudo update-rc.d /etc/init.d/myservice defaults
ссылки
Я написал /etc/init.d/spark_shutdown.sh и создал ссылку в /etc/rc0.d & /etc/rc6.d, как мне подтвердить, что этот скрипт запускался в экземпляре ubuntu aws ec2
Ашиш Карпе,
10

Теперь, когда варианты Ubuntu и Mint перешли на systemd, я обнаружил, что мои старые решения, основанные на вышеизложенном, были менее удовлетворительными. Я искал в Интернете, чтобы выяснить, как это сделать с помощью systemd, и в итоге объединил чужую мудрость и задокументировал ее как пост в блоге на blogspot.com.au, содержащий следующее руководство.

С помощью systemd вы создаете один или два файла для вызова ваших сценариев, используя приведенные ниже шаблоны, и выполняете пару команд. Просто.


Версия GUI

Сначала создайте сценарии, которые вы хотите запустить при запуске и / или завершении работы. Я создал .scopening_atstart и .scfullcopy_atend.

Затем убедитесь, что они оба исполняемые, щелкнув правой кнопкой мыши по файлу, выбрав свойства и убедившись, что в соответствии с разрешениями вы отметили Разрешить выполнение файла как программы.

Два файла, которые я создал, заполняют и сохраняют содержимое виртуального диска. Они также создают файл в моем домашнем каталоге, чтобы доказать, что служба работает. Они были в форме:

#!/bin/sh
cp -pru /home/john/zRamdisk/subdirectory1/* /home/john/.wine/drive_c/subdirectory1/
rm /home/john/stop_time
date +%D' '%T > /home/john/stop_time

Затем я открыл свой файловый менеджер как root, открыл /etc/systemd/systemи создал файл startup.service и файл save-ramdisk.service. Очевидно, что вы можете выбрать свои собственные имена, и общие имена могли включать файл запуска с именем johns_start.service и файл завершения работы с именем johns_shutdown.service. Просто не выбирайте названия существующих сервисов.

[Unit]
Description=Startup Applications

[Service]
Type=oneshot
RemainAfterExit=false
ExecStart=/home/john/.scopening_atstart

[Install]
WantedBy=multi-user.target

а также

[Unit]
Description=Save Ramdisk to Wine drive C

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/true
ExecStop=/home/john/.scfullcopy_atend

[Install]
WantedBy=multi-user.target

Вы можете использовать те же служебные файлы, заменяя мой полный путь к исполняемому скрипту.

Наконец, для каждого из них выполните команду systemctl enable your_files_name (но без службы суффиксов). Так что мой первый былsystemctl enable startup

Перезагрузите компьютер один раз, чтобы запустить службы. Служба запуска будет выполняться всякий раз, когда systemd входит в многопользовательскую цель, и службу остановки, когда она выходит из многопользовательской цели. Альтернативные сервисные файлы с различными условиями активации будут описаны ниже.


CLI (командная строка) версия

В этом описании предполагается, что вы работаете из своего домашнего каталога, а не / home / john, используете sudo по мере необходимости и ваш выбор редактора, где я пишу vim или svim.

Создайте сценарии оболочки запуска и завершения работы с первой строкой #!/bin/shи сделайте их исполняемыми с помощью chmod +x my_new_filename.

Создайте два файла, как указано выше, или в этом примере один файл для обработки задач запуска и завершения работы. Я буду выполнять скрипты в своем домашнем каталоге, но @don_crissti показывает некоторые альтернативы в Stack Exchange .

vim /etc/systemd/system/start_and_stop.service

и скопируйте в файл содержимое:

[Unit]
Description=Run Scripts at Start and Stop

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/home/john/.startup_commands  #your paths and filenames
ExecStop=/home/john/.shutdown_commands

[Install]
WantedBy=multi-user.target

Затем включите службу с помощью команды:

systemctl enable start_and_stop

и перезагрузите систему, после чего службы будут активны. Команды systemctl is-enabled start_and_stopи systemctl is-active start_and_stopмогут быть использованы в мониторинге ваших новых сервисов.


Изменение условий запуска для выключения

Прежде всего файлы используют открытие или закрытие многопользовательской среды для запуска сценариев. Файл ниже использует начало четырех возможных процессов выключения для запуска своих сценариев. Добавление или удаление целей в строке «До» + в строке «WantedBy» позволит вам сделать более четкие различия:

Этот файл был предложен во втором ответе этого поста, но я не смог его запустить, пока не добавил раздел «Установка».

Снова отредактируйте скрипт /etc/systemd/service/и включите его, используя systemctl enable your_file_name. Когда я изменил цели, я использовал systemclt disable file_nameкоманду, а затем снова включил ее, что символически связало ее с целевыми каталогами. Перезагрузитесь и сервис будет работать.

[Unit]
Description=Do something required
DefaultDependencies=no
Before=shutdown.target reboot.target halt.target
# This works because it is installed in the target and will be
#   executed before the target state is entered
# Also consider kexec.target

[Service]
Type=oneshot
ExecStart=/home/john/.my_script  #your path and filename

[Install]
WantedBy=halt.target reboot.target shutdown.target
Иоанн 9631
источник
7

Вам нужно использовать rc.shutdownскрипт завершения работы для ядра Linux. Цитирование справочной страницы OpenBSD :

Когда система выключается с помощью команд reboot (8) или halt (8), или когда для этого выдается сигнал init (8), или когда выдается запрос на остановку, запрошенный клавиатурой (если архитектура поддерживает это), rc ( 8) вызывается с аргументом `` shutdown ''.

Итак, вы просто открываете свой rc.shutdown и добавляете в него все команды оболочки, которые хотите выполнить.

ОБНОВЛЕНИЕ: Поскольку Linux Mint основан на Ubuntu, который имеет другую процедуру запуска / выключения, вот процедура, относящаяся к вам:

Напишите сценарий оболочки, который вы хотите выполнить, и скопируйте его в соответствующий каталог в вашем /etc/rc*.d/. В *соответствует уровень запуска , на котором вы хотите, чтобы скрипт для выполнения.
Ubuntu следует нумерации уровней запуска Debian, поэтому у вас есть уровень запуска 0 для остановки и уровень запуска 6 для перезагрузки.

darnir
источник
1

Для систем инициализации, основанных на зависимостях SysV, используемых в Debian Wheezy, Devuan и его производных и, возможно, других, вы можете имитировать поведение rc.shutdownаналога, rc.localкак показано ниже:

Добавьте свои команды к следующему скелету /etc/rc.shutdown:

#!/bin/sh -e
#
# rc.shutdown
#

# <add your commands here, before exit 0>

exit 0

Сохраните скрипт и сделайте файл исполняемым с помощью chmod a+x /etc/rc.shutdown.

Затем добавьте /etc/init.d/rc.shutdownв вашу систему новый скрипт со следующим содержимым:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          rc.shutdown
# Required-Start:
# Required-Stop:
# X-Stop-After:      umountroot
# Default-Start:
# Default-Stop:      0 6
# Short-Description: Run /etc/rc.shutdown if it exist
### END INIT INFO


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

. /lib/init/vars.sh
. /lib/lsb/init-functions

do_stop() {
    if [ -x /etc/rc.shutdown ]; then
            [ "$VERBOSE" != no ] && log_begin_msg "Running local shutdown scripts (/etc/rc.shutdown)"
        /etc/rc.shutdown
        ES=$?
        [ "$VERBOSE" != no ] && log_end_msg $ES
        return $ES
    fi
}

case "$1" in
    start)
        # No-op
        ;;
    restart|reload|force-reload)
        echo "Error: argument '$1' not supported" >&2
        exit 3
        ;;
    stop|status)
    do_stop
        exit 0
        ;;
    *)
        echo "Usage: $0 start|stop" >&2
        exit 3
        ;;
esac

Также сделайте этот скрипт исполняемым.

Создайте символические ссылки в /etc/rc[06].d:

cd /etc/rc0.d ; ln -s ../init.d/rc.shutdown K01rc.shutdown

а также

cd /etc/rc6.d ; ln -s ../init.d/rc.shutdown K01rc.shutdown

Используйте insservдля исправления символических ссылок и создания необходимых файлов .depend.boot, .depend.start и .depend.stop:

insserv -v

Вы должны быть пользователем root или использовать sudo для всех команд, упомянутых выше.

Адриан Заугг
источник
Сегодня я потратил немного времени на это и не смог заставить его работать с Ubuntu 16, возможно, это был я, но решение выше сработало немедленно.
Майк Q