今天看到一个和有趣的项目 undistract-me( github /jml/undistract-me)。它可以在命令执行时间超过指定时间的情况下,在命令执行完毕后通过 notify-send 发送通知告诉你。
我对它的实现很好奇,于是阅读了一下它的源代码。从它的代码中又学到了很多关于BASH的知识:
使用 command -v 命令,根据 man bash 中的说法:
command [-pVv] command [arg ...]
运行 command ,使用 args 作为参数,禁止通常的查找 shell
函数的过程。只有内建命令或者 PATH 中包含的命令可以执行。如果给出
-p 参数, command 的查找是以 PATH
的默认值进行的。这样可以保证找到所有的标准工具。如果给出 -V 或者
-v 选项,关于 command 的说明将被打印出来。 -v
选项使得表述这个命令的词,或者要执行 command
需要执行的文件显示出来; -V 选项给出更详细的描述。如果给出 -V
或者 -v 选项,退出状态在找到了 command 的情况下0,没找到就是1。
如果没有提供选项,并且产生了错误或者 command
没有找到,退出状态就是127。否则, command 内建命令的退出状态是
command 的退出状态。
通过 FUNCNAME 可以获取到当前执行的shell函数名
函数执行时, FUNCNAME 变量被设置为函数的名称。
${BASH_SOURCE[0]} 可以去的当前执行函数所在shell文件的路径
BASH_SOURCE
An array variable whose members are the source filenames where
the corresponding shell function names in the FUNCNAME array
variable are defined. The shell function ${FUNCNAME[$i]} is
defined in the file ${BASH_SOURCE[$i]} and called from
${BASH_SOURCE[$i+1]}.
该变量中的值会在每次现实主提示符之前执行
PROMPT_COMMAND
If set, the value is executed as a command prior to issuing each
primary prompt.
BASH_COMMAND 变量存储的是正在执行的命令:
BASH_COMMAND
The command currently being executed or about to be executed,
unless the shell is executing a command as the result of a trap,
in which case it is the command executing at the time of the
trap.
local this_command=$(HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//g"); # 当带管道时,$BASH_COMMAND就不准确了
记得这里要把环境变量 HISTTIMEFORMAT 清空,因为它可能影响到 history 的输出格式
HISTTIMEFORMAT
If this variable is set and not null, its value is used as a
format string for strftime(3) to print the time stamp associated
with each history entry displayed by the history builtin. If
this variable is set, time stamps are written to the history
file so they may be preserved across shell sessions. This uses
the history comment character to distinguish timestamps from
other history lines.
undistract-me 巧妙的利用了 DEBUG trap 和 PROMPT_COMMAND 变量,首先,通过DEBUG trap,在每次命令执行前将要执行的命令,执行的时间以及执行命令时的窗口id号存储起来(通过 history)
然后,通过变量 PROMPT_COMMAND 在出现主提示符(也就是命令执行完后)前计算一下当前时间和当前激活的窗口 id 号, 如果时间间隔超过指定时间并且激活的窗口改变了就调用 notify-send 来发送通知了。

