Уведомление рабочего стола о завершении длительных команд


59

Я хотел бы получать уведомление на рабочем столе всякий раз, когда команда, которая выполняется более 15 секунд, завершается в интерактивной оболочке.

Другими словами, я бы хотел, чтобы все команды были обернуты примерно так

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

Какой лучший способ сделать это в bash?




Почему вы добавили «в интерактивной оболочке» только сейчас? Это может сделать недействительными некоторые из существующих ответов, которые существовали в контексте вашего исходного сообщения более года. Если вам нужно решение специально для интерактивной оболочки, подумайте над тем, чтобы задать этот вопрос отдельно.
Сергей Колодяжный

Часть «Интерактивная оболочка» была разъяснена в первом комментарии перед редактированием. Я просто отредактировал вопрос и удалил комментарий. Кроме того, 3 строки, размещенные в вопросах, хорошо работают для сценария.
17

Ответы:


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

Useage

wrapper <your_command>

Если это займет более 15 секунд, вы получите уведомление на рабочем столе, описывающее команду и время ее выполнения.

пример

wrapper sudo apt-get update

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


1
"$@"Не $@. Большая разница.
гейра

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

SNAP1

Вы можете настроить псевдоним в соответствии с вашими потребностями и желаниями.


3
Это приятно знать. Есть ли способ добавить оповещение после каждой вводимой команды (а также иметь оповещение только в том случае, если команда заняла более 15 секунд)?
aioobe

странная вещь, это уже добавлено в мой .bashrc, это по умолчанию в Ubuntu?
Вигнеш

13

Помимо обертки, подобной предложенной souravc, на самом деле нет хорошего способа сделать это в bash. Вы можете обойти это, используя ловушку DEBUG и PROMPT_COMMAND. Ловушка DEBUG срабатывает всякий раз, когда вы запускаете команду, и PROMPT_COMMAND запускается непосредственно перед написанием приглашения.

Так что вещи для ~/.bashrcчто-то вроде

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

Это хак, так что не удивляйтесь, если с этим столкнетесь со странными побочными эффектами.


4

РЕДАКТИРОВАТЬ

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

Человек, который назначил награду за этот вопрос, сказал:

«Все существующие ответы требуют ввода дополнительной команды после команды. Мне нужен ответ, который делает это автоматически».

При изучении решений этой проблемы я наткнулся на этот вопрос из stackexchange, который позволяет связать CtrlJпоследовательность команд: Ctrla(переместиться в начало строки), поместите строку «mesure» перед введенной вами командой Ctrlm(execute)

Таким образом, вы получаете функциональность автозаполнения и отдельную 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но для просмотра вывода перенаправление в файл также может быть сделано.

ИМХО, гораздо лучший подход - отправлять вывод времени в какой-то файл в вашей домашней папке (просто чтобы вы не загрязняли вашу систему временными файлами и всегда знали, где искать). Вот эта вторая версия

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отлично работают для сценариев Unix bash. Это требуется интерпретатору сценария, чтобы он знал, какой это тип сценария.

Это похоже на тестовый скрипт:

#!/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.


Почему мой ответ был отклонен? Я хочу знать, где я ошибся в ответе
Rumesh

Я не отрицал это, но я скажу вам, что с ним не так: во-первых, это требует ввода дополнительной команды. Я специально заявил в своей награде, что не хочу этого делать. Во-вторых, зачем рассчитывать? $((2+2))является встроенным в Bash, не требует никаких дополнительных программ. Третье: он не работает с командами, которые имеют пробелы. tl; dr: это хуже, чем другие ответы 1-летнего возраста
Galgalesh

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