Повідомлення на робочому столі, коли виконуються тривалі команди


59

Я хотів би отримувати сповіщення на робочому столі, коли команда, яка виконується більше, скажімо, 15 секунд, закінчується в інтерактивній оболонці.

Іншими словами, я хотів би, щоб усі команди були загорнуті у щось подібне

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

Який найкращий спосіб досягти цього в баші?




Чому ви додали "в інтерактивну оболонку" саме зараз? Це може визнати недійсними деякі відповіді, які існували у вашій оригінальній публікації більше року. Якщо вам потрібне рішення спеціально для інтерактивної оболонки, розгляньте питання про окреме запитання, посилаючись на це.
Сергій Колодяжний

Частина "інтерактивної оболонки" була уточнена в першому коментарі перед редагуванням. Я просто відредагував питання і видалив коментар. Крім того, 3 рядки, розміщені у запитаннях, добре справляються зі сценарієм.
aioobe

Відповіді:


24

Ви хочете https://launchpad.net/undistract-me (встановлюється з архівів Ubuntu з sudo apt-get install undistract-me), який виконує саме те, що ви просите, в тому числі працюючи автоматично (тобто, не пам'ятаючи, щоб додати щось додаткове для потенційно довгострокового, виконання команд).


1
Схоже, це не працює. Я встановив його, перезавантажив систему та перевірив sleep 30, але сповіщення не було.
Галгалеш

4
Вам необхідно додати наступні два рядки .bashrc: . /usr/share/undistract-me/long-running.bash notify_when_long_running_commands_finish_install. Здається, це помилка: github.com/jml/undistract-me/issues/23
Ludenticus

32

Наскільки я зрозумів, ти хочеш обгортку . І ви хочете використовувати команду через неї, щоб вона дала вам бажане сповіщення, якщо час роботи вашої команди перевищує 15 сек. Так ось це.

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

Скопіюйте цю функцію у свій ~/.bashrcта джерело ~/.bashrcяк,

. ~/.bashrc

Використання

wrapper <your_command>

Якщо це займе більше 15 секунд, ви отримаєте сповіщення на робочому столі, що описує команду та час її виконання.

Приклад

wrapper sudo apt-get update

скріншот робочого столу-нітифікація


1
"$@", не $@. Велика різниця.
geirha

4
Я хотів би уникати написання wrapperперед кожною командою, яку я набираю.
aioobe

2
@aioobe ви можете використовувати коротше ім'я функції, навіть може бути буквою. але обгортка працює таким чином.
souravc

3
command; alertнасправді коротше, ніж wrapper command:-)
aioobe

1
Якщо ви не хочете, notify-sendщоб термін дії закінчувався тривалий час, тоді дайте сповіщення-надішліть спеціальний тайм-аут (у мілісекундах). наприкладnotify-send --expire-time 999999999 ...
Брайс Гінта

26

У ~/.bashrcпсевдонімі alertвизначено:

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

які можна використовувати для сповіщення про завершення виконання команди.

Використання:

$ the_command; alert

напр

$ sudo apt-get update; alert

оснащення1

Ви можете налаштувати псевдонім відповідно до ваших потреб та бажання.


3
Це приємно знати. Чи є спосіб додавати попередження після кожної команди, яку я набираю (а також надсилати її попередження, лише якщо команда займає більше 15 секунд)?
aioobe

дивна річ, вона вже додана до мого .bashrc, це за замовчуванням в ubuntu?
Виньєш

13

Крім обгортки, як запропоновано souravc, насправді немає жодного хорошого способу зробити це в баші. Ви можете зламати його навколо за допомогою DEPUG пастки та PROMPT_COMMAND. DEPUG пастка запускається кожного разу, коли ви запускаєте команду, і PROMPT_COMMAND запускається безпосередньо перед записом запису.

Тож начинки ~/.bashrcстають чимось на кшталт

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

Це злом, тому не дивуйтеся, якщо зіткнетеся з незвичайними побічними ефектами.


4

EDIT

TL; DR : створити ярлик автоматичного завершення .inputrcі функціонувати в .bashrc . Запустіть команду, як зазвичай, введіть, але замість цього ENTERнатисніть ярлик, який ви вказали.inputrc

Людина, яка розмістила щедрість за це питання, сказала:

"Усі існуючі відповіді вимагають ввести додаткову команду після команди. Я хочу відповідь, яка робить це автоматично".

Під час дослідження рішень цієї проблеми я натрапив на це запитання від stackexchange, що дозволяє прив’язати CtrlJдо послідовності команд: Ctrla(перехід до початку рядка), розмістіть рядок "mesure" перед командою, яку ви ввели, Ctrlm(виконайте)

Таким чином, ви отримуєте функцію автоматичного завершення та окрему ENTERкоманду для вимірювання часу, дотримуючись початкового призначення другої функції, яку я розмістив нижче.

На сьогодні тут вміст мого ~/.inputrcфайлу:

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

І ось вміст .bashrc(зауважте, я не використовую bash назавжди - я використовую mksh як свою оболонку, отже, це ви бачите в оригінальній публікації. Функціональність все одно однакова)

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


}

Оригінальна публікація

Ось моя ідея - використовувати функцію в .bashrc. Основний принцип - використовуйте /usr/bin/timeдля вимірювання часу, необхідного для виконання команди, і, якщо це більше 15 секунд, надішліть повідомлення.

function measure () 
{

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

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

fi


}

Тут я переадресовую вихід, /dev/nullале щоб переглянути вихід, також можна зробити переадресацію до файлу.

Набагато кращим підходом, IMHO, є надсилання часу на якийсь файл у вашій домашній папці (тільки щоб ви не забруднювали систему тимчасовими файлами та завжди знали, де шукати). Ось ця друга версія

function measure () 
{

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

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

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

fi


}

А ось скріншоти першої та другої версій, в такому порядку

Перша версія, без вихідних даних введіть тут опис зображення

Друга версія, з виходом введіть тут опис зображення


До речі, працює і з командами sudo. Я тестував це з sudo lsofі в основному з ping -c20 google.com.
Сергій Колодяжний

3

Нещодавно я створив інструмент, який служить цій цілі. Вона може бути запущена як обгортка або автоматично з інтеграцією оболонки. Перевірте це тут: http://ntfy.rtfd.io

Щоб встановити його:

sudo pip install ntfy

Щоб використовувати його як обгортку:

ntfy done sleep 3

Щоб автоматично отримувати сповіщення, додайте це до свого .bashrcабо .zshrc:

eval "$(ntfy shell-integration)"

1

Ваш сценарій працює досить добре, просто переконайтеся, що ви включили рядок 'shebang' ( #!/bin/bash) . Інші #!/bin/bashзгадані тут , але більшу частину часу #!/bin/bashдобре спрацьовують для скриптів bash Unix. Його вимагає інтерпретатор сценарію, щоб він знав, що це за сценарій.

Це, здається, працює як тестовий сценарій:

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

Щоб змінити цей скрипт, поставте команду (и), де знаходяться echoі sleepрядки.

Зверніть увагу на notify-send, що ви можете -iтакож вказати піктограму :-)

Також переконайтеся, що він виконується, попередньо запустивши chmod +x /PATH/TO/FILEйого.


1

Ви можете змінити Bash, щоб реалізувати потрібну функцію обгортки.

Якщо ви схильні вносити багато таких модифікацій у свою інтерактивну оболонку, ви можете розглянути можливість переходу на суто іскробезпечну оболонку, наприклад eshell, яка побудована за допомогою Emacs elisp та має всі свої істотні налаштування:

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


-2

Ви також можете зробити це за допомогою простого, якщо подібне твердження

#!/bin/bash

START=$(date +%s)

TIME=$(($START+15))

ORIGINAL_COMMAND;

END=$(date +%s)

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

Ви можете використовувати власні імена змінних.

Я можу підтвердити, що це працює, я перевірив команду, яка потребує тривалого часу, і завершити цю функцію - ні, і повідомлення надходить для тієї, що займає тривалий час

Ви також можете зробити це з будь-якою командою, замінивши ORIGINAL_COMMANDз $@і запустити скрипт як ./script command.


Чому мою відповідь було знято? Хочу знати, де я помилився у відповіді
Румеш

Я не спровокував це, але скажу вам, що з цим не так: Перш за все, для цього потрібно ввести додаткову команду. Я спеціально заявив, що не бажаю цього робити. По-друге, чому кальку? $((2+2))це bash вбудований, не потребує додаткових програм. По-третє: він не працює з командами, які мають пробіли. tl; dr: це гірше, ніж інші відповіді на 1 рік
Галгалеш

Ну ..... час початку та закінчення завжди буде іншим, правда? Навіть за коротку команду, що триває 1 секунду
Сергій Колодяжний
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.