Notificação da área de trabalho quando comandos de execução longa são concluídos

59

Gostaria de receber uma notificação na área de trabalho sempre que um comando que tenha sido executado por mais de, digamos 15 segundos, termine em um shell interativo.

Em outras palavras, eu gostaria que todos os comandos fossem agrupados em algo assim

start=$(date +%s);
ORIGINAL_COMMAND;
[ $(($(date +%s) - start)) -le 15 ] || notify-send "Long running command finished"

Qual é a melhor maneira de fazer isso no bash?

aioobe
fonte
11
Possível mesmo no Superusuário: superuser.com/questions/31917/…
Ciro Santilli escreveu
Por que você adicionou "no shell interativo" agora? Isso pode invalidar algumas das respostas existentes que existem no contexto de sua postagem original há mais de um ano. Se você precisar de uma solução específica para o shell interativo, considere fazer uma pergunta separada com referência a esta.
Sergiy Kolodyazhnyy 5/05
A parte do "shell interativo" foi esclarecida no primeiro comentário antes da edição. Simplesmente editei a pergunta e removi o comentário. Além disso, as três linhas postadas nas perguntas funcionam bem para um script.
Aioobe 5/05

Respostas:

24

Você deseja https://launchpad.net/undistract-me (instalável a partir dos arquivos do Ubuntu sudo apt-get install undistract-me) que faz exatamente o que você está solicitando, incluindo o trabalho automático (ou seja, sem ter que se lembrar de adicionar algo extra para potencialmente longo- comandos em execução).

sil
fonte
11
Não parece estar funcionando. Eu instalei, reiniciei o sistema e testei com sleep 30, mas sem notificação.
Galgalesh
4
Você precisa adicionar as duas linhas seguintes .bashrc: . /usr/share/undistract-me/long-running.bash notify_when_long_running_commands_finish_install. Parece ser um bug: github.com/jml/undistract-me/issues/23
Ludenticus 27/11/16
32

Tanto quanto eu entendi, você quer um invólucro . E você deseja usar um comando através dele para que ele lhe dê a notificação desejada se o tempo de execução do seu comando for superior a 15 segundos. Então aqui está.

wrapper(){
    start=$(date +%s)
    "$@"
    [ $(($(date +%s) - start)) -le 15 ] || notify-send "Notification" "Long\
 running command \"$(echo $@)\" took $(($(date +%s) - start)) seconds to finish"
}

Copie esta função no seu ~/.bashrce source ~/.bashrccomo,

. ~/.bashrc

Uso

wrapper <your_command>

Se demorar mais de 15 segundos, você receberá a notificação da área de trabalho descrevendo o comando e seu tempo de execução.

Exemplo

wrapper sudo apt-get update

captura de tela do desktop-nitification

souravc
fonte
11
"$@"não $@. Grande diferença.
Geirha
4
Eu gostaria de evitar escrever wrapperna frente de cada comando digitado.
aioobe
2
@aioobe, você pode usar um nome de função mais curto, mesmo que seja uma letra. mas um wrapper funciona dessa maneira.
souravc
3
command; alerté na verdade menor do que wrapper command:-)
aioobe
11
Se você não deseja que o notify-sendprazo de validade expire por um longo período, forneça um tempo limite personalizado para notificação / envio (em milissegundos). por exemplo,notify-send --expire-time 999999999 ...
Bryce Guinta
26

No ~/.bashrcexiste um alias alertdefinido como:

alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'

que pode ser usado para notificar a conclusão da execução do comando.

Uso:

$ the_command; alert

por exemplo

$ sudo apt-get update; alert

snap1

Você pode personalizar o alias conforme sua necessidade e desejo.

preciso
fonte
3
É bom Saber. Existe uma maneira de acrescentar alerta após cada comando digitado (e também alertá-lo apenas se o comando levar mais de 15 segundos)?
aioobe
coisa estranha que já foi adicionada ao meu .bashrc, é padrão no ubuntu?
Vignesh
13

Além de um invólucro como souravc sugerido, não há realmente nenhuma boa maneira de fazer isso no bash. Você pode invadir o local com uma interceptação DEBUG e um PROMPT_COMMAND. Uma interceptação DEBUG é acionada sempre que você executa um comando e PROMPT_COMMAND é executado imediatamente antes da gravação do prompt.

Então, coisas para ~/.bashrcse tornam algo como

trap '_start=$SECONDS' DEBUG
PROMPT_COMMAND='(if (( SECONDS - _start > 15 )); then notify-send "Long running command ended"; fi)'

Isso é um truque, então não se surpreenda se você encontrar efeitos colaterais estranhos com isso.

Geirha
fonte
4

EDITAR

TL; DR : criar atalho de preenchimento automático .inputrce funcionar em .bashrc . Execute o comando como de costume, digite, mas, em vez de ENTER, pressione o atalho especificado em.inputrc

A pessoa que colocou recompensa nessa questão disse:

"Todas as respostas existentes exigem a digitação de um comando adicional após o comando. Quero uma resposta que faça isso automaticamente."

Enquanto pesquisava as soluções para esse problema, eu me deparei com essa pergunta no stackexchange, que permite a ligação CtrlJa uma sequência de comandos: Ctrla(vá para o início da linha), coloque a string "mesure" na frente do comando que você digitou, Ctrlm(execute)

Assim, você obtém a funcionalidade de preenchimento automático e ENTERcomando separado para medir o tempo, enquanto mantém o objetivo original da segunda função que publiquei abaixo.

A partir de agora, aqui está o conteúdo do meu ~/.inputrcarquivo:

"\C-j": "\C-a measure \C-m"

E aqui está o conteúdo de .bashrc(note, eu não uso o bash há sempre - eu uso o mksh como meu shell, portanto é isso que você vê no post original. A funcionalidade ainda é a mesma)

PS1=' serg@ubuntu [$(pwd)]
================================
$ '
function measure () 
{

/usr/bin/time --output="/home/xieerqi/.timefile" -f "%e" $@ 

if [ $( cat ~/.timefile| cut -d'.' -f1 ) -gt 15 ]; then

    notify-send "Hi , $@ is done !"

fi


}

Correio Original

Aqui está a minha ideia - usar uma função no .bashrc. Princípio básico - use /usr/bin/timepara medir o tempo necessário para a conclusão do comando e, se demorar mais de 15 segundos, envie uma notificação.

function measure () 
{

if [ $( /usr/bin/time -f "%e" $@ 2>&1 >/dev/null ) -gt 15 ]; then

    notify-send "Hi , $@ is done !"

fi


}

Aqui estou redirecionando a saída para, /dev/nullmas para visualizar a saída, o redirecionamento para o arquivo também pode ser feito.

Uma abordagem muito melhor, IMHO, é enviar saída de tempo para algum arquivo na sua pasta pessoal (apenas para você não poluir seu sistema com arquivos de tempo e sempre saber para onde procurar). Aqui está a segunda versão

function measure () 
{

/usr/bin/time --output=~/.timefile -f "%e" $@ 

if [ $( cat ~/.timefile | cut -d'.' -f1 ) -gt 15 ]; then

    notify-send "Hi , $@ is done !"

fi


}

E aqui estão as capturas de tela da primeira e da segunda versão, nessa ordem

Primeira versão, sem saída insira a descrição da imagem aqui

Segunda versão, com saída insira a descrição da imagem aqui

Sergiy Kolodyazhnyy
fonte
A propósito, também funciona com comandos sudo. Eu testei com sudo lsofe principalmente com ping -c20 google.com.
Sergiy Kolodyazhnyy
3

Recentemente, criei uma ferramenta que serve a esse propósito. Ele pode ser executado como um wrapper ou automaticamente com a integração do shell. Confira aqui: http://ntfy.rtfd.io

Para instalá-lo:

sudo pip install ntfy

Para usá-lo como um invólucro:

ntfy done sleep 3

Para receber notificações automaticamente, adicione-o ao seu .bashrcou .zshrc:

eval "$(ntfy shell-integration)"
Daniel Schep
fonte
1

Seu script funciona muito bem, apenas inclua a linha 'shebang' ( #!/bin/bash) . Outros #!/bin/bashmencionados aqui , mas na maioria das vezes, #!/bin/bashfuncionam bem para scripts bash do Unix. É exigido pelo interpretador de script para que ele saiba que tipo de script é.

Isso parece funcionar como um script de teste:

#!/bin/bash
start=$(date +%s);
   echo Started
   sleep 20;
   echo Finished!
[ $(($(date +%s) - start)) -le 15 ] || notify-send -i dialog-warning-symbolic "Header" "Message"

Para modificar esse script, coloque o (s) comando (s) onde estão as linhas echoe sleep.

Observe que notify-send, você também pode -iespecificar um ícone :-)

Além disso, verifique se ele é executável executando chmod +x /PATH/TO/FILE-o primeiro.

Wilf
fonte
1

Você pode modificar o Bash para implementar a funcionalidade do wrapper desejada.

Se você está disposto a fazer muitas modificações no seu shell interativo, considere mudar para um shell intrinsecamente hackável como o eshell, que é construído usando o Emacs elisp e tem toda a sua capacidade de personalização:

http://www.masteringemacs.org/articles/2010/12/13/complete-guide-mastering-eshell/

Ryan Prior
fonte
-2

Você também pode fazer isso com uma declaração if simples como esta

#!/bin/bash

START=$(date +%s)

TIME=$(($START+15))

ORIGINAL_COMMAND;

END=$(date +%s)

if [ $END -gt $TIME ]
then
    notify-send "Task Completed"
fi

Você pode usar seus próprios nomes de variáveis.

Posso confirmar que isso funciona, testei com um comando que demora muito para terminar e um que não funciona e a notificação chega para aquele que demora muito

Você também pode fazer isso com qualquer comando, substituindo ORIGINAL_COMMANDcom $@e executar o script como ./script command.

Rumesh
fonte
Por que minha resposta foi reduzida? Eu quero saber onde eu errei na resposta
Rumesh
Não diminuí a votação, mas vou lhe dizer o que há de errado com isso: primeiro, é necessário digitar um comando adicional. Eu afirmei especificamente na minha recompensa que não quero fazer isso. Em segundo lugar, por que calcular? $((2+2))é um bash embutido, não requer nenhum programa adicional. Terceiro: não funciona com comandos que possuem espaços. tl; dr: é pior que as outras respostas de 1 ano
Galgalesh
Bem ..... o horário de início e fim sempre será diferente, certo? Mesmo para um comando curto que tem 1 segundo de comprimento
Sergiy Kolodyazhnyy 4/16