Como o script Bash pode matar a versão “adormecida” de si mesmo já em execução?

4

Editar A partir dos comentários abaixo, eu escrevi uma introdução confusa / enganosa, então estou reescrevendo-a.

Eu tenho um script bash chamado " timer da tela de bloqueio " que pode ser clicado na área de trabalho. Após 30 minutos, ele bloqueia a tela e o usuário precisa digitar sua senha para desbloquear a tela. No entanto, se o usuário mudar de idéia ou quiser redefinir o cronômetro, ele poderá clicar no atalho da área de trabalho novamente e deverá interromper o trabalho anterior em execução, que está em espera e na contagem regressiva.

Eu fiz um pequeno teste e erro até agora e acertei um bloqueio.

O snippet de código relevante é:

pgrep tv-timer > ~/tv-timer.log
PID=$$ # Current Process ID

Usando cat ~/tv-timer.log :

16382
20711

Um deles é igual a "$ PID" acima, mas o outro é uma cópia em execução anterior, que eu quero usar kill ##### .

Qual é a melhor maneira de descobrir qual delas < > "$ PID" e matá-lo?

A primeira vez que o script é executado, há apenas uma entrada igual a "$ PID", que eu não quero matar.

Obrigado pela sua ajuda!

A duplicata proposta ( Impede que o script duplicado seja executado no sametime ) é um problema nos processos Pai e Filho . As respostas aceitas são longas e complicadas, envolvendo scripts de wrapper e / ou várias linhas de código.

A solução procurada aqui é uma linha de novo código!

De fato, a resposta aceito-eleito aqui é baseada em uma tentativa OP duplicada que NÃO FUNCIONA LÁ!

    
por WinEunuuchs2Unix 13.11.2016 / 02:48

2 respostas

3
Tendo passado muitas horas seguindo o coelho branco em vários universos alternativos, descobri que o único método confiável é:

# If called a second time, kill the first version already running
kill $(pgrep -f "${0##*/}" | grep -v ^$$)

Se você está interessado em testar isto, veja Lock Screen Timer code em Ask Ubuntu em: ( Application que bloqueará a tela após um período de tempo definido para o Ubuntu

Snippet de código da versão de produção (TL; DR)

O trecho de código pertinente do programa lock-screen-timer é este:

# Check if lock screen timer already running
pID=$(pgrep -f "${0##*/}") # All PIDs matching lock-screen-timer name
PREVIOUS=$(echo "$pID" | grep -v ^"$$") # Strip out this running copy ($$$)
if [ $PREVIOUS != "" ]; then
    zenity --info --title="Lock screen timer already running" --text="Previous lock screen timer has been terminated."
    kill "$PREVIOUS"
fi

pgrep -f "${0##*/}"

Isso localiza todas as ocorrências do mesmo ID de programa em execução nomeado ${0##*/} . Embora o arquivo executável seja chamado de ~/bin/lock-screen-timer , um atalho da área de trabalho é usado para chamá-lo. Isso pode ser chamado de "Lock Screen Timer" ou "Lock screen timer" ou "Lembrar-me do ciclo de roupa". Não pode ser codificado no programa como na pergunta original.

A lista resultante de ids do processo é colocada na variável $pID

echo "$pID" | grep -v ^"$$"

Isso pega o conteúdo de $pID (todas as ocorrências em execução de lock-screen-timer ou é renomeado atalho na área de trabalho) e canaliza a lista de ids do processo para o próximo comando usando o caractere pipe ( | ).

O próximo comando grep -v remove os IDs do processo que correspondem a $$ , que é o ID do processo em execução atual. A cenoura ( ^ ) diz ao grep que corresponde à palavra inteira e não à cadeia de caracteres. Por exemplo, o ID do processo atual pode ser 1518 e a versão anterior pode ser 11518 , 21518 ou 31518 . Nesse caso, apenas correspondendo em 4 dígitos o ID do processo faz essas 3 correspondências porque 1518 está dentro de 11518 . A cenoura combina com palavras assim 1518 < > %código%. Na lista id do processo, as palavras são separadas por espaços (em uma variável) ou por novos caracteres de linha (quando o comando 11518 os exibe na tela).

O resultado desses dois comandos é o ID do processo do script ps -aux executado anteriormente. O ID do processo é colocado na variável lock-screen-timer . Se não houver um ID anterior, o valor será "" (campo nulo).

$PREVIOUS

Isso testa se if [ $PREVIOUS != "" ]; then não é igual a ( $PREVIOUS ) um campo nulo / vazio != . Obviamente, nós só podemos matar um ID de processo anteriormente em execução se tivermos um!

""

Ao executar um atalho na área de trabalho, você não pode zenity --info --title="Lock screen timer already running" ... mensagens para o usuário porque a GUI não as exibe. Eles acabam em echo e você precisa exibi-los com /var/log/syslog ou cat , etc.

gedit é um ótimo programa para exibir caixas de diálogo e formulários do bash para o zenity (Graphical User Interface), também conhecido como Desktop. O texto da mensagem continua dizendo O temporizador da tela de bloqueio anterior foi encerrado. . Isso permite que o usuário inicie uma nova contagem regressiva do temporizador ou simplesmente cancele. Em essência, chamando o script uma segunda vez e abortando é como você pode matar o primeiro script já em execução.

GUI

Isso simplesmente mata a versão anterior que queremos fazer, se iniciarmos uma nova contagem regressiva kill "$PREVIOUS" ou não. Isso é substancialmente diferente da pergunta original porque colocamos os resultados de dois comandos ocultos na única variável chamada lock-screen-timer .

    
por WinEunuuchs2Unix 13.11.2016 / 04:10
4

Por favor, mude a linha:

pgrep tv-timer | grep -v $$ > ~/tv-timer2.log

para isso:

pgrep tv-timer | grep -v ^$$$ > ~/tv-timer2.log

Na verdade, se um tv-timer prosesses tiver, digamos, PID = 26019 e $$ for 6019, então o grep renderia uma string vazia, que não é o que você quer.

    
por Alessandro 13.11.2016 / 17:17