Notification du bureau lorsque de longues commandes sont terminées

59

J'aimerais recevoir une notification sur le bureau chaque fois qu'une commande exécutée depuis plus de, disons, 15 secondes se termine dans un shell interactif.

En d'autres termes, je voudrais que toutes les commandes soient emballées dans quelque chose comme ceci

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

Quelle est la meilleure façon d'accomplir cela à bash?

aioobe
la source
1
Même chose possible sur le super
Ciro Santilli a été ajouté
Pourquoi avez-vous ajouté "dans un shell interactif" tout à l'heure? Cela pourrait invalider certaines des réponses existantes qui existaient dans le contexte de votre message d'origine depuis plus d'un an. Si vous avez besoin d’une solution spécifique au shell interactif, envisagez de poser une question distincte référençant celle-ci.
Sergiy Kolodyazhnyy
La partie "shell interactif" a été clarifiée dans le premier commentaire avant la modification. J'ai simplement édité la question et enlevé le commentaire. De plus, les 3 lignes affichées dans les questions fonctionnent bien pour un script.
aioobe

Réponses:

24

Vous voulez https://launchpad.net/undistract-me (installable à partir des archives Ubuntu avec sudo apt-get install undistract-me) qui fait exactement ce que vous demandez, y compris le travail automatique (c'est-à-dire, sans avoir à vous rappeler d'ajouter quelque chose d'extra les commandes en cours).

sil
la source
1
Cela ne semble pas fonctionner. Je l'ai installé, j'ai redémarré mon système et testé avec sleep 30, mais sans notification.
Galgalesh
4
Vous devez ajouter les deux lignes suivantes .bashrc: . /usr/share/undistract-me/long-running.bash notify_when_long_running_commands_finish_install. Cela semble être un bug: github.com/jml/undistract-me/issues/23
Ludenticus
32

Autant que je sache, vous voulez un emballage . Et vous voulez utiliser une commande à travers elle pour qu'elle vous donne la notification souhaitée si le temps d'exécution de votre commande est supérieur à 15 secondes. Alors voilà.

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

Copiez cette fonction dans votre ~/.bashrcet source ~/.bashrccomme,

. ~/.bashrc

Utilisation

wrapper <your_command>

Si cela prend plus de 15 secondes, vous recevrez la notification du bureau décrivant la commande et son heure d'exécution.

Exemple

wrapper sudo apt-get update

capture d'écran de la nitification de bureau

souravc
la source
1
"$@", Non $@. Grande différence.
geirha
4
J'aimerais éviter d'écrire wrapperdevant chaque commande que je tape cependant.
aioobe
2
@aioobe, vous pouvez utiliser un nom de fonction plus court, même une lettre. mais un emballage fonctionne de cette manière.
Souravc
3
command; alertest en fait plus court que wrapper command:-)
aioobe
1
Si vous ne souhaitez pas que le notify-sendcontrat expire pendant une longue période, donnez à notify-send un délai d'expiration personnalisé (en millisecondes). par exemplenotify-send --expire-time 999999999 ...
Bryce Guinta
26

Dans ~/.bashrcil y a un alias alertdéfini comme:

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

qui peut être utilisé pour notifier l'achèvement de l'exécution de la commande.

Usage:

$ the_command; alert

par exemple

$ sudo apt-get update; alert

claquer1

Vous pouvez personnaliser le pseudonyme selon vos besoins et vos désirs.

précis
la source
3
C'est bon à savoir. Existe-t-il un moyen d’ajouter une alerte après chaque commande que je tape (et de l’avertir uniquement si la commande a pris plus de 15 secondes)?
aioobe
Chose étrange, il est déjà ajouté à mon .bashrc, est-ce par défaut dans Ubuntu?
Vignesh
13

À part un emballage comme suggéré par souravc, il n’existe pas vraiment de bonne façon de faire cela en bash. Vous pouvez y faire un détour avec un piège DEBUG et un PROMPT_COMMAND. Une interruption DEBUG est déclenchée chaque fois que vous exécutez une commande et PROMPT_COMMAND est exécuté juste avant l'écriture de l'invite.

Donc, ça ~/.bashrcdevient quelque chose comme

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

Ceci est un hack, alors ne soyez pas surpris si vous rencontrez des effets secondaires bizarres avec cela.

geirha
la source
4

MODIFIER

TL; DR : crée un raccourci d’auto-complétion dans .inputrcet fonctionne dans .bashrc . Exécutez la commande comme d'habitude, tapez, mais au lieu de ENTER, appuyez sur le raccourci que vous avez spécifié dans.inputrc

La personne qui a placé la prime sur cette question a déclaré:

"Toutes les réponses existantes nécessitent la saisie d'une commande supplémentaire après la commande. Je veux une réponse qui le fasse automatiquement."

En recherchant les solutions à ce problème, je suis tombé par hasard sur cette question de stackexchange, qui permet de lier CtrlJune séquence de commandes: Ctrla(déplacer au début de la ligne), placez la chaîne "mesure" devant la commande que vous avez entrée, Ctrlm(execute)

Ainsi, vous obtenez une fonctionnalité d’auto-complétion et une ENTERcommande séparée pour la mesure du temps, tout en préservant le but initial de la deuxième fonction affichée ci-dessous.

Pour l'instant, voici le contenu de mon ~/.inputrcdossier:

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

Et voici le contenu de .bashrc(remarque, je n’utilise pas bash depuis toujours - j’utilise mksh comme shell, c’est ce que vous voyez dans le message original. Les fonctionnalités sont toujours les mêmes)

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


}

Poste originale

Voici mon idée - utiliser une fonction dans .bashrc. Principe de base - utilisez-le /usr/bin/timepour mesurer le temps nécessaire à l'exécution de la commande et, s'il dépasse 15 secondes, envoyez une notification.

function measure () 
{

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

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

fi


}

Ici, je redirige la sortie vers /dev/nullmais pour visualiser la sortie, la redirection vers un fichier peut également être effectuée.

Une approche bien meilleure, à mon humble avis, consiste à envoyer la sortie de temps à un fichier de votre dossier de départ (afin que vous ne polluiez pas votre système avec des fichiers de temps et que vous sachiez toujours où regarder). Voici cette deuxième version

function measure () 
{

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

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

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

fi


}

Et voici les captures d'écran des première et deuxième versions, dans cet ordre

Première version, pas de sortie entrez la description de l'image ici

Deuxième version, avec sortie entrez la description de l'image ici

Sergiy Kolodyazhnyy
la source
À propos, fonctionne aussi avec les commandes sudo. Je l'ai testé avec sudo lsofet surtout avec ping -c20 google.com.
Sergiy Kolodyazhnyy
3

J'ai récemment construit un outil qui sert cet objectif. Il peut être exécuté en tant que wrapper ou automatiquement avec l’intégration du shell. Découvrez-le ici: http://ntfy.rtfd.io

Pour l'installer:

sudo pip install ntfy

Pour l'utiliser comme un wrapper:

ntfy done sleep 3

Pour recevoir des notifications automatiquement, ajoutez ceci à votre .bashrcou .zshrc:

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

Votre script fonctionne assez bien, assurez-vous simplement d'inclure la ligne 'shebang' ( #!/bin/bash) . Les autres à #!/bin/bashsont mentionnés ici , mais la plupart du temps, cela #!/bin/bashfonctionne très bien pour les scripts bash Unix. Il est requis par l'interpréteur de script pour qu'il sache de quel type de script il s'agit.

Cela semble fonctionner comme un script de 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"

Pour modifier ce script, placez la ou les commandes où se trouvent les lignes echoet sleep.

Notez que notify-sendvous pouvez également utiliser -iune icône pour spécifier une icône :-)

Assurez-vous également qu'il est exécutable en l'exécutant chmod +x /PATH/TO/FILEd'abord.

Wilf
la source
1

Vous pouvez modifier Bash pour implémenter la fonctionnalité d'encapsulage souhaitée.

Si vous êtes enclin à apporter de nombreuses modifications de ce type à votre shell interactif, vous pouvez envisager de passer à un shell intrinsèquement hackable comme eshell, construit à l'aide d'Emacs elisp et doté de toutes ses possibilités de personnalisation:

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

Ryan Prior
la source
-2

Vous pouvez également le faire avec une simple déclaration if comme celle-ci.

#!/bin/bash

START=$(date +%s)

TIME=$(($START+15))

ORIGINAL_COMMAND;

END=$(date +%s)

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

Vous pouvez utiliser vos propres noms de variables.

Je peux confirmer que cela fonctionne, j'ai testé avec une commande qui prend beaucoup de temps et qui ne fonctionne pas, et la notification est fournie pour celle qui prend beaucoup de temps.

Vous pouvez également le faire avec n'importe quelle commande en remplaçant ORIGINAL_COMMANDpar $@et en exécutant le script en tant que ./script command.

Rumesh
la source
Pourquoi ma réponse a-t-elle été mise aux voix? Je veux savoir où je me suis trompé dans
ma
Je n'ai pas eu le vote négatif, mais je vais vous dire ce qui ne va pas. Tout d'abord, il faut taper une commande supplémentaire. J'ai expressément déclaré dans ma prime que je ne voulais pas faire cela. Deuxièmement, pourquoi calc? $((2+2))est une bash intégrée, ne nécessite aucun programme supplémentaire. Troisièmement: cela ne fonctionne pas avec les commandes qui ont des espaces. tl; dr: c'est pire que l'autre réponse d'un an
Galgalesh
Eh bien ... les heures de début et de fin seront toujours différentes, non? Même pour une commande courte qui dure 1 seconde
Sergiy Kolodyazhnyy