长时间运行的命令完成后的桌面通知


59

每当在交互式外壳中运行了超过15秒的命令时,我都希望收到桌面通知。

换句话说,我希望所有命令都被包装成这样

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

在bash中完成此操作的最佳方法是什么?




您为什么现在才添加“在交互式外壳中”?这可能会使在您的原始帖子中存在超过一年的现有答案无效。如果您需要专门针对交互式Shell的解决方案,请考虑询问引用此问题的单独问题。
谢尔盖·科洛迪亚兹尼

在编辑之前的第一条评论中,“交互式外壳”部分得到了澄清。我只是编辑了问题并删除了评论。此外,问题中张贴的3行内容对于脚本来说效果很好。
aioobe '17

Answers:


24

您想要https://launchpad.net/undistract-me(可从Ubuntu归档文件安装,具有sudo apt-get install undistract-me),它可以精确地满足您的要求,包括自动工作(也就是说,无需记住为可能很长的时间添加额外的内容,运行命令)。


1
它似乎不起作用。我安装了它,重新启动了系统并使用进行了测试sleep 30,但没有任何通知。
2015年

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
"$@"不是$@。巨大差距。
盖尔哈2014年

4
不过,我想避免wrapper在我键入的每个命令之前编写代码。
aioobe 2014年

2
@aioobe可以使用较短的函数名,甚至可以是字母。但是包装器以这种方式工作。
souravc 2014年

3
command; alert实际上比短wrapper command:-)
aioobe

1
如果您不想notify-send长时间过期,请给通知发送自定义超时(以毫秒为单位)。例如notify-send --expire-time 999999999 ...
Bryce Guinta '17

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 2014年

它已经添加到我的.bashrc中,这很奇怪,在ubuntu中默认吗?
Vignesh

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(执行)

因此,您可以获得自动完成功能和ENTER用于测量时间的单独命令,同时保留了我在下面介绍的第二个功能的原始目的。

到目前为止,这是我~/.inputrc文件的内容:

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

这是.bashrc(请注意,我从未永远使用bash-我使用mksh作为我的shell,因此这就是您在原始帖子中看到的内容。功能仍然相同)

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
Sergiy Kolodyazhnyy,2015年

3

我最近构建了一个用于此目的的工具。它既可以作为包装程序运行,也可以与Shell集成一起自动运行。在这里查看:http : //ntfy.rtfd.io

要安装它:

sudo pip install ntfy

要将其用作包装器:

ntfy done sleep 3

要自动获取通知,请将其添加到您的.bashrc或中.zshrc

eval "$(ntfy shell-integration)"

1

您的脚本运行良好,只需确保包含“ shebang” #!/bin/bash行即可。这里#!/bin/bash要提到的其他脚本,但是在大多数情况下,对于Unix bash脚本来说效果很好。脚本解释器需要它,因此它知道脚本的类型。#!/bin/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"

要修改此脚本,请将命令放在echosleep行所在的位置。

注意notify-send,您还可以使用-i它指定图标:-)

另外,请先运行chmod +x /PATH/TO/FILE它以确保它是可执行的。



-2

您也可以使用简单的if语句来执行此操作

#!/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;博士:它比其他1岁的答案更糟
Galgalesh

好吧.....开始和结束时间总是会有所不同,对吧?即使是很短的命令是1秒长
谢尔盖Kolodyazhnyy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.