Notificación de escritorio cuando se completan los comandos de larga ejecución

59

Me gustaría recibir una notificación de escritorio cada vez que un comando que se haya ejecutado durante más de 15 segundos, termine en un shell interactivo.

En otras palabras, me gustaría que todos los comandos se envuelvan en algo como esto

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

¿Cuál es la mejor manera de lograr esto en bash?

aioobe
fuente
1
Posible lo mismo en Superusuario: superuser.com/questions/31917/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
¿Por qué agregaste "en shell interactivo" justo ahora? Podría invalidar algunas de las respuestas existentes que existieron en el contexto de su publicación original durante más de un año. Si necesita una solución específica para shell interactivo, considere hacer una pregunta por separado haciendo referencia a esta.
Sergiy Kolodyazhnyy
La parte de "shell interactivo" se aclaró en el primer comentario antes de la edición. Simplemente edité la pregunta y eliminé el comentario. Además, las 3 líneas publicadas en las preguntas funcionan bien para un guión.
aioobe

Respuestas:

24

Desea https://launchpad.net/undistract-me (instalable desde los archivos de Ubuntu con sudo apt-get install undistract-me) que hace exactamente lo que está pidiendo, incluido el trabajo automático (es decir, sin tener que acordarse de agregar algo extra a un tiempo potencialmente largo) ejecutando comandos).

sil
fuente
1
No parece estar funcionando. Lo instalé, reinicié mi sistema y probé con sleep 30, pero sin notificación.
Galgalesh
44
Es necesario añadir las dos líneas siguientes .bashrc: . /usr/share/undistract-me/long-running.bash notify_when_long_running_commands_finish_install. Parece ser un error: github.com/jml/undistract-me/issues/23
Ludenticus el
32

Según tengo entendido, quieres un envoltorio . Y desea usar un comando a través de él para que le dé la notificación deseada si el tiempo de ejecución de su comando es más de 15 segundos. Así que aquí 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 función en su ~/.bashrcy fuente ~/.bashrccomo,

. ~/.bashrc

Uso

wrapper <your_command>

Si tarda más de 15 segundos, recibirá la notificación de escritorio que describe el comando y su tiempo de ejecución.

Ejemplo

wrapper sudo apt-get update

captura de pantalla de la nitificación de escritorio

souravc
fuente
1
"$@", No $@. Gran diferencia.
geirha
44
Sin wrapperembargo, me gustaría evitar escribir delante de cada comando que escribo .
aioobe
2
@aioobe puede usar un nombre de función más corto, incluso puede ser una letra. pero un contenedor funciona de esta manera.
souravc
3
command; alertde hecho es más corto que wrapper command:-)
aioobe
1
Si no desea notify-sendque caduque por un tiempo prolongado, envíe un tiempo de espera personalizado a notificar y enviar (en milisegundos). por ejemplonotify-send --expire-time 999999999 ...
Bryce Guinta el
26

En ~/.bashrchay un 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 se puede usar para notificar la finalización de la ejecución del comando.

Uso:

$ the_command; alert

p.ej

$ sudo apt-get update; alert

snap1

Puede personalizar el alias según sus necesidades y deseos.

preciso
fuente
3
Es bueno saberlo. ¿Hay alguna forma de agregar alertas después de cada comando que escribo (y también hacer que se active solo si el comando tardó más de 15 segundos)?
aioobe
Lo extraño ya está agregado a mi .bashrc, ¿está predeterminado en ubuntu?
Vignesh
13

Además de una envoltura como la sugerida por souravc, en realidad no hay una buena manera de hacer esto en bash. Puedes hackearlo con una trampa DEBUG y un PROMPT_COMMAND. Cuando se ejecuta un comando, se activa una captura DEBUG y PROMPT_COMMAND se ejecuta justo antes de que se escriba la solicitud.

Así que las cosas se ~/.bashrcconvierten en algo así como

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

Este es un truco, así que no te sorprendas si encuentras efectos secundarios extraños con esto.

geirha
fuente
4

EDITAR

TL; DR : crea un acceso directo de autocompletado .inputrcy funciona en .bashrc . Ejecute el comando como de costumbre, escriba, pero en lugar de ENTER, presione el acceso directo que especificó en.inputrc

La persona que puso recompensa por esta pregunta dijo:

"Todas las respuestas existentes requieren escribir un comando adicional después del comando. Quiero una respuesta que haga esto automáticamente".

Mientras investigaba las soluciones a este problema, me topé con esta pregunta desde stackexchange, que permite vincular CtrlJa una secuencia de comandos: Ctrla(mover al comienzo de la línea), colocar la cadena "mesure" delante del comando que ingresó, Ctrlm(ejecutar)

Por lo tanto, obtiene la funcionalidad de autocompletar y un ENTERcomando separado para medir el tiempo, al tiempo que conserva el propósito original de la segunda función que publiqué a continuación.

A partir de ahora, aquí están los contenidos de mi ~/.inputrcarchivo:

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

Y aquí están los contenidos de .bashrc(nota, no he estado usando bash para siempre, uso mksh como mi shell, por lo tanto, eso es lo que ves en la publicación original. La funcionalidad sigue siendo la misma)

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


}

Publicación original

Aquí está mi idea: use una función en .bashrc. Principio básico: utilícelo /usr/bin/timepara medir el tiempo que tarda el comando en completarse y, si es superior a 15 segundos, envíe una notificación.

function measure () 
{

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

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

fi


}

Aquí estoy redirigiendo la salida, /dev/nullpero para ver la salida, también se puede hacer la redirección al archivo.

Un enfoque mucho mejor, en mi humilde opinión, es enviar la salida de tiempo a algún archivo en su carpeta de inicio (solo para que no contamine su sistema con archivos de tiempo y siempre sepa dónde buscar). Aquí está esa segunda versión

function measure () 
{

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

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

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

fi


}

Y aquí están las capturas de pantalla de la primera y segunda versión, en ese orden

Primera versión, sin salida ingrese la descripción de la imagen aquí

Segunda versión, con salida ingrese la descripción de la imagen aquí

Sergiy Kolodyazhnyy
fuente
Por cierto, también funciona con comandos sudo. Lo he probado con sudo lsofy principalmente con ping -c20 google.com.
Sergiy Kolodyazhnyy
3

Recientemente construí una herramienta que sirve para este propósito. Puede ejecutarse como un contenedor o automáticamente con integración de shell. Compruébalo aquí: http://ntfy.rtfd.io

Para instalarlo:

sudo pip install ntfy

Para usarlo como envoltorio:

ntfy done sleep 3

Para recibir notificaciones automáticamente, agregue esto a su .bashrco .zshrc:

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

Su script funciona bastante bien, solo asegúrese de incluir la línea 'shebang' ( #!/bin/bash) . Otros que #!/bin/bashse mencionan aquí , pero la mayoría de las veces, #!/bin/bashfunciona bien para los scripts bash Unix. Es requerido por el intérprete de guiones para que sepa qué tipo de guión es.

Esto parece funcionar como un script de prueba:

#!/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 este script, coloque los comandos donde están las líneas echoy sleep.

Tenga en cuenta notify-sendque también puede usar -ipara especificar un icono :-)

Además, asegúrese de que sea ejecutable ejecutándolo chmod +x /PATH/TO/FILEprimero.

Wilf
fuente
-2

También puede hacer esto con una simple declaración if 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

Puede usar sus propios nombres de variables.

Puedo confirmar que esto funciona, lo probé con un comando que tarda mucho en terminar y otro que no funciona, y la notificación llega para el que lleva mucho tiempo

También puede hacer esto con cualquier comando mediante la sustitución ORIGINAL_COMMANDcon $@y ejecutar el script como ./script command.

Rumesh
fuente
¿Por qué mi respuesta fue rechazada? Quiero saber dónde me equivoqué en la respuesta
Rumesh
No lo rechacé, pero le diré qué tiene de malo: en primer lugar, requiere escribir un comando adicional. Dije específicamente en mi recompensa que no quiero hacer eso. En segundo lugar, ¿por qué calc? $((2+2))es un bash incorporado, no requiere ningún programa adicional. Tercero: no funciona con comandos que tienen espacios. tl; dr: es peor que las otras respuestas de 1 año
Galgalesh
Bueno ... la hora de inicio y finalización siempre será diferente, ¿verdad? Incluso para un comando corto que dura 1 segundo
Sergiy Kolodyazhnyy