Notifica desktop al termine dei comandi di lunga durata


59

Vorrei ricevere una notifica desktop ogni volta che un comando eseguito per più di, diciamo 15 secondi, termina in una shell interattiva.

In altre parole, vorrei che tutti i comandi fossero racchiusi in qualcosa del genere

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

Qual è il modo migliore per ottenere questo risultato in bash?




Perché hai aggiunto "nella shell interattiva" proprio ora? Potrebbe invalidare alcune delle risposte esistenti che esistevano nel contesto del tuo post originale per oltre un anno. Se hai bisogno di una soluzione specifica per la shell interattiva, considera di porre una domanda separata facendo riferimento a questa.
Sergiy Kolodyazhnyy,

La parte "shell interattiva" è stata chiarita nel primo commento prima della modifica. Ho semplicemente modificato la domanda e rimosso il commento. Inoltre, le 3 righe pubblicate nelle domande funzionano bene per uno script.
aioobe,

Risposte:


24

Vuoi https://launchpad.net/undistract-me (installabile dagli archivi Ubuntu con sudo apt-get install undistract-me) che fa esattamente quello che stai chiedendo, incluso lavorare automaticamente (cioè, senza dover ricordare di aggiungere qualcosa in più a potenzialmente lungo- comandi in esecuzione).


1
Non sembra funzionare. L'ho installato, riavviato il mio sistema e testato con sleep 30, ma nessuna notifica.
Galgalesh,

4
È necessario aggiungere le seguenti due righe a .bashrc: . /usr/share/undistract-me/long-running.bash notify_when_long_running_commands_finish_install. Sembra essere un bug: github.com/jml/undistract-me/issues/23
Ludenticus

32

Per quanto ho capito, vuoi un involucro . E vuoi usare un comando attraverso di esso in modo che ti dia la notifica desiderata se il tempo di esecuzione del tuo comando è superiore a 15 sec. Quindi eccolo qui.

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

Copia questa funzione nel tuo ~/.bashrce sorgente ~/.bashrccome,

. ~/.bashrc

Usage

wrapper <your_command>

Se impiega più di 15 secondi, riceverai una notifica sul desktop che descrive il comando e il suo tempo di esecuzione.

Esempio

wrapper sudo apt-get update

screenshot di desktop-nitification


1
"$@"no $@. Grande differenza.
geirha,

4
Vorrei evitare di scrivere wrapperdavanti a ogni comando che scrivo però.
Aioobe,

2
@aioobe è possibile utilizzare un nome di funzione più breve, anche se può essere una lettera. ma un wrapper funziona in questo modo.
souravc,

3
command; alertè in effetti più breve di wrapper command:-)
aioobe

1
Se non si desidera notify-sendche scada a lungo, assegnare a notifica-invio un timeout personalizzato (in millisecondi). ad es.notify-send --expire-time 999999999 ...
Bryce Guinta,

26

In ~/.bashrcc'è un alias alertdefinito come:

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$//'\'')"'

che può essere utilizzato per notificare il completamento dell'esecuzione del comando.

Uso:

$ the_command; alert

per esempio

$ sudo apt-get update; alert

snap1

Puoi personalizzare l'alias secondo le tue necessità e desideri.


3
È bello sapere. Esiste un modo per aggiungere un avviso dopo ogni comando che scrivo (e anche avere un avviso solo se il comando ha impiegato più di 15 secondi)?
Aioobe,

cosa strana è già stata aggiunta al mio .bashrc, è di default in Ubuntu?
Vignesh,

13

A parte un involucro come suggerito souravc, non c'è davvero alcun buon modo per farlo in bash. Puoi aggirarti con una trappola DEBUG e un PROMPT_COMMAND. Una trap DEBUG viene attivata ogni volta che si esegue un comando e PROMPT_COMMAND viene eseguito subito prima della scrittura del prompt.

Quindi roba per ~/.bashrcdiventa qualcosa di simile

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

Questo è un trucco, quindi non sorprenderti se incontri strani effetti collaterali con questo.


4

MODIFICARE

TL; DR : crea il collegamento al completamento automatico .inputrce funzione in .bashrc . Esegui il comando come al solito, digita, ma invece di ENTER, premi il collegamento che hai specificato.inputrc

La persona che ha posto la grazia a questa domanda ha detto:

"Tutte le risposte esistenti richiedono di digitare un comando aggiuntivo dopo il comando. Voglio una risposta che lo faccia automaticamente."

Durante la ricerca delle soluzioni a questo problema mi sono imbattuto in questa domanda da StackExchange, che consente l'associazione CtrlJa una sequenza di comandi: Ctrla(sposta all'inizio della riga), posiziona la stringa "mesure" davanti al comando che hai inserito, Ctrlm(esegui)

In questo modo ottieni funzionalità di auto-completamento e ENTERcomando separato per misurare il tempo, pur mantenendo lo scopo originale della seconda funzione che ho pubblicato qui sotto.

A partire da ora, ecco i contenuti del mio ~/.inputrcfile:

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

Ed ecco il contenuto di .bashrc(nota, non uso mai bash da sempre - uso mksh come shell, quindi è quello che vedi nel post originale. La funzionalità è sempre la stessa)

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


}

Posta originale

Ecco la mia idea: utilizzare una funzione in .bashrc. Principio di base: utilizzare /usr/bin/timeper misurare il tempo necessario per il completamento del comando e, se è superiore a 15 secondi, inviare una notifica.

function measure () 
{

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

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

fi


}

Qui sto reindirizzando l'output /dev/nullma per visualizzare l'output, è possibile eseguire anche il reindirizzamento al file.

Un approccio molto migliore, IMHO, è di inviare l'output di tempo ad alcuni file nella cartella home (solo per non inquinare il sistema con i file temporali e sapere sempre dove cercare). Ecco quella seconda versione

function measure () 
{

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

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

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

fi


}

Ed ecco gli screenshot della prima e della seconda versione, in questo ordine

Prima versione, nessun output inserisci qui la descrizione dell'immagine

Seconda versione, con output inserisci qui la descrizione dell'immagine


A proposito, funziona anche con i comandi sudo. L'ho provato con sudo lsofe principalmente con ping -c20 google.com.
Sergiy Kolodyazhnyy,

3

Di recente ho creato uno strumento che serve a questo scopo. Può essere eseguito come wrapper o automaticamente con l'integrazione della shell. Dai un'occhiata qui: http://ntfy.rtfd.io

Per installarlo:

sudo pip install ntfy

Per usarlo come wrapper:

ntfy done sleep 3

Per ricevere automaticamente le notifiche, aggiungilo al tuo .bashrco .zshrc:

eval "$(ntfy shell-integration)"

1

Il tuo script funziona abbastanza bene, assicurati di includere la riga 'shebang' ( #!/bin/bash) . Altri #!/bin/bashcitati qui , ma il più delle volte, #!/bin/bashfunzionano bene con gli script Unix bash. È richiesto dall'interprete di script in modo da sapere che tipo di script è.

Questo sembra funzionare come uno script di test:

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

Per modificare questo script, inserisci i comandi in corrispondenza delle righe echoe sleep.

Nota con notify-send, puoi usare anche -iper specificare un'icona :-)

Inoltre, assicurati che sia eseguibile eseguendolo chmod +x /PATH/TO/FILEprima.



-2

Puoi anche farlo con una semplice istruzione if come questa

#!/bin/bash

START=$(date +%s)

TIME=$(($START+15))

ORIGINAL_COMMAND;

END=$(date +%s)

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

Puoi usare i tuoi nomi di variabili.

Posso confermare che funziona, ho testato con un comando che richiede molto tempo per terminare e uno che non funziona e la notifica arriva per quella che richiede molto tempo

È anche possibile fare questo con qualsiasi comando, sostituendo ORIGINAL_COMMANDcon $@e l'esecuzione dello script come ./script command.


Perché la mia risposta è stata sottoposta a downgrade? Voglio sapere dove ho sbagliato nella risposta
Rumesh

Non l'ho sottovalutato, ma ti dirò cosa c'è che non va: prima di tutto, è necessario digitare un comando aggiuntivo. Ho espressamente dichiarato nella mia taglia che non voglio farlo. In secondo luogo, perché calc? $((2+2))è un built-in bash, non richiede programmi aggiuntivi. Terzo: non funziona con i comandi che hanno spazi. tl; dr: è peggio delle risposte
dell'altro

Bene ..... l'orario di inizio e fine sarà sempre diverso, giusto? Anche per un breve comando che dura 1 secondo
Sergiy Kolodyazhnyy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.