Execute um comando antes do desligamento

52

Quero executar um comando simples antes de o computador desligar (o tempo não é essencial).

Para a inicialização, eu posso usar /etc/rc.local; existe algo semelhante para o desligamento?

Observe que eu ainda gostaria de usar o botão de desligamento integrado no menu; ou seja, não quero usar um script personalizado toda vez que desligar pelo terminal - ele precisa ser automático.

Primož Kralj
fonte

Respostas:

42

O Linux Mint é baseado no Ubuntu, então estou convencido de que o sistema de nível de execução provavelmente é o mesmo. No Ubuntu, os scripts para os diferentes níveis de execução são executados de acordo com sua presença nos /etc/rc[0-6].ddiretórios. O nível de execução 0 corresponde ao desligamento e 6 à reinicialização.

Normalmente, o próprio script é armazenado /etc/init.de os links simbólicos são colocados nos diretórios correspondentes aos níveis de execução necessários.

Portanto, no seu caso, escreva seu script, armazene-o e /etc/init.d/, em seguida, crie um link simbólico em cada um /etc/rc0.de /etc/rc6.d(se você quiser os dois) apontando para o script.

Os scripts em cada diretório do nível de execução serão executados em ordem asciótica , portanto, se a ordem no nível de execução for importante para você, escolha o nome do seu link simbólico adequadamente.

ire_and_curses
fonte
Eu apenas dei uma olhada no arquivo de esqueleto no init.d (kubuntu preciso) e fiquei um pouco intimidado. Eu só quero adicionar alguns comandos que ecoam a data do desligamento em um arquivo em / var / log. Posso fazer isso ou tenho que lidar com algumas das outras coisas no arquivo do esqueleto?
Joe
2
@ Joe - Você não precisa da maioria dessas coisas, a menos que queira que seu script seja controlável como um serviço padrão. Você não quebrará nada com um eco simples no seu próprio arquivo de log, então tente e veja.
ire_and_curses
11
Aqui está um exemplo simples de script init.d. Além disso, é mais fácil e mais robusto criar os links simbólicos usando:sudo update-rc.d /etc/init.d/myservice defaults
RolfBly
Eu escrevi /etc/init.d/spark_shutdown.sh e criei o link em /etc/rc0.d & /etc/rc6.d agora como eu confirmo que esse script foi executado na instância do ubuntu aws ec2
Ashish Karpe
10

Agora que as variantes do Ubuntu e o Mint foram para o systemd, achei minhas soluções antigas com base no exposto menos satisfatórias. Pesquisei na web para descobrir como fazer isso com o systemd e acabei combinando a sabedoria de outras pessoas e documentando-a como uma postagem de blog em blogspot.com.au contendo o seguinte tutorial.

Com o systemd, você cria um ou dois arquivos para chamar seus scripts usando os modelos abaixo e executa alguns comandos. Simples.


Versão da GUI

Primeiro, crie os scripts que você deseja executar na inicialização e / ou desligamento. Criei .scopening_atstart e .scfullcopy_atend.

Em seguida, verifique se eles são executáveis ​​clicando com o botão direito do mouse no arquivo, selecionando propriedades e certificando-se de que, em permissões, você tenha marcado Permitir a execução de arquivo como um programa.

Os dois arquivos que eu criei preenchem e salvam o conteúdo de um ramdisk. Eles também criam um arquivo no meu diretório pessoal para provar que o serviço está funcionando. Eles tinham a forma:

#!/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

Em seguida , abri meu gerenciador de arquivos como root, abri /etc/systemd/systeme criei um arquivo startup.service e um arquivo save-ramdisk.service. Obviamente, você pode escolher seus próprios nomes e nomes genéricos poderiam incluir um arquivo de inicialização chamado johns_start.service e um arquivo de desligamento chamado johns_shutdown.service. Apenas não escolha nomes de serviço existentes.

[Unit]
Description=Startup Applications

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

[Install]
WantedBy=multi-user.target

e

[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

Você pode usar os mesmos arquivos de serviço, substituindo o caminho completo do seu script executável pelo meu.

Finalmente, para cada um, execute o comando systemctl enable your_files_name (mas sem o serviço de sufixo). Então meu primeiro foisystemctl enable startup

Reinicie o computador uma vez para iniciar os serviços. O serviço inicial será executado sempre que o systemd entrar no destino multiusuário e o serviço de parada quando sair do destino multiusuário. Arquivos de serviço alternativos com diferentes condições de ativação serão descritos abaixo.


Versão CLI (linha de comando)

Esta descrição supõe que você opere no diretório inicial em vez de em / home / john, use o sudo conforme necessário e sua escolha do editor em que escrevo vim ou svim.

Crie scripts de shell de inicialização e desligamento com a primeira linha #!/bin/she torne-os executáveis ​​usando chmod +x my_new_filename.

Crie dois arquivos como acima, ou neste exemplo, um arquivo para lidar com tarefas de inicialização e desligamento. Vou executar scripts no meu diretório pessoal, mas o @don_crissti mostra algumas alternativas no Stack Exchange .

vim /etc/systemd/system/start_and_stop.service

e copie o conteúdo do arquivo:

[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

Ative o serviço com o comando:

systemctl enable start_and_stop

e reinicie o sistema após o qual os serviços estarão ativos. Os comandos systemctl is-enabled start_and_stope systemctl is-active start_and_stoppodem ser usados ​​no monitoramento de seus novos serviços.


Alterando as condições do acionador para desligamento

Os arquivos acima de tudo usam a abertura ou o fechamento do ambiente multiusuário para iniciar a execução dos scripts. O arquivo abaixo usa o início de quatro possíveis processos de desligamento para iniciar seus scripts. Adicionar ou remover os destinos na linha Antes + na linha WantedBy permitirá fazer distinções mais refinadas:

Este arquivo foi proposto na segunda resposta desta postagem, mas não consegui executá-lo até que eu adicionei uma seção Instalação.

Novamente, edite o script /etc/systemd/service/e ative-o usando systemctl enable your_file_name. Quando alterei os destinos, usei o systemclt disable file_namecomando e o reativei, que o vinculou aos diretórios de destino. Reinicialize e o serviço estará operando.

[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
John 9631
fonte
7

Você precisa usar rc.shutdowno script de desligamento para o kernel do Linux. Citando a página de manual do OpenBSD :

Quando o sistema é desligado usando os comandos reboot (8) ou halt (8), ou quando init (8) é sinalizado para fazê-lo, ou quando uma interrupção solicitada pelo teclado é emitida (se a arquitetura suportar), rc ( 8) é invocado com o argumento `` shutdown ''.

Então, você simplesmente abre seu rc.shutdown e adiciona os comandos shell que deseja executar.

ATUALIZAÇÃO: Como o Linux Mint é baseado no Ubuntu, que possui um procedimento diferente de inicialização / desligamento, eis o procedimento relevante para você:

Escreva o shell script que você deseja executar e copie-o para o diretório relevante no seu /etc/rc*.d/. Os *corresponde ao nível de execução no qual deseja que o script para executar.
O Ubuntu segue a numeração do nível de execução do Debian, então você tem o nível de execução 0 para parada e o nível de execução 6 para reinicialização.

darnir
fonte
1

Para sistemas init baseados em dependências SysV usados ​​no Debian Wheezy, Devuan e seus derivados e talvez outros, você pode imitar o comportamento do rc.shutdownanalógico para rc.localgostar do seguinte:

Adicione seus comandos ao seguinte esqueleto de /etc/rc.shutdown:

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

# <add your commands here, before exit 0>

exit 0

Salve o script e torne o arquivo executável com chmod a+x /etc/rc.shutdown.

Em seguida, adicione um novo script /etc/init.d/rc.shutdownao seu sistema com o seguinte conteúdo:

#! /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

Também torne este script executável.

Crie os links simbólicos em /etc/rc[06unette.d:

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

e

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

Use insservpara corrigir os links simbólicos e criar os arquivos .depend.boot, .depend.start e .depend.stop necessários:

insserv -v

Você precisa ser root ou usar o sudo para todos os comandos mencionados acima.

Adrian Zaugg
fonte
Hoje perdi meu tempo com este e não consegui fazê-lo funcionar com o Ubuntu 16, talvez fosse eu, mas a solução acima funcionou imediatamente.
Mike Q