让费时命令执行完推送到 Telegram

工作时,常遇到需要执行很麻瓜久的命令,比如说 apt update && apt upgrade,或是给手机刷机、跑个测试等,动辄几十分钟。在下不可能傻乎乎的阻塞在这一个命令上,而是会切换上下文去干别的事情。

当任务完成之后,在下希望 shell 通知到在下,而不是在下反复去轮询它。

通过研究,发现开发者友好的 Telegram 适合干这个事情。

效果图

下面就来传授步骤:

第一步,装个 Telegram,用起来。

第二步,按照这个链接的步骤,创建一个 Bot,并记下 API KEY。

第三步,在电脑上装好 telegram-send。 其实就是 $ pip3 install telegram-send 这个软件就是这篇文章的精髓了,以前也没想到还能有这种软件。

还有这种软件?!

第四步,在电脑上配置 telegram-send,要用到第二步的 API KEY。 $ telegram-send --configure

第五步,在 ~/.bashrc 或者 ~/.bash_profile 添加如下代码。

# push a notification when a long-time command finished
# prefix: _TGPN
function _TGPN_precommand_cbk() {
  [[ -z "$_TGPN_AT_PROMPT" ]] && return
  unset _TGPN_AT_PROMPT

  _TGPN_CMD="$BASH_COMMAND"
  _TGPN_TELEGRAM_NOTIFY_START_TIME=$(date +%s)
}
trap '_TGPN_precommand_cbk' DEBUG

_TGPN_FIRST_PROMPT=1
function _TGPN_postcommand_cbk() {
  _TGPN_AT_PROMPT=1

  if [ -n "$_TGPN_FIRST_PROMPT" ]; then
    unset _TGPN_FIRST_PROMPT
    return
  fi

  local NOW=$(date +%s)
  local DIFFERENCE=$(( $NOW - ${_TGPN_TELEGRAM_NOTIFY_START_TIME:-0} ))
  _TGPN_THRESHOLD=10
  _TGPN_IGNORE=$(cat <<EOF
^adb shell
^vi
^nano
^ssh
^man
^mail
^ftp
EOF
)
  [[ $DIFFERENCE -gt $_TGPN_THRESHOLD ]] && { 
    for pattern in $_TGPN_IGNORE; do
      echo $_TGPN_CMD | grep -qE $pattern && return
    done
    echo "发现了上条命令执行了很久,推送执行完毕信息到 Telegram"; 
    echo $_TGPN_CMD
    telegram-send "✅$_TGPN_CMD" &
  }
}
PROMPT_COMMAND="_TGPN_postcommand_cbk"

其中有两个可配置项: _TGPN_THRESHOLD 是指的超过多少秒的命令需要推送告知; _TGPN_IGNORE 是一堆以换行分隔的 grep 风格的正则表达式,表示命令中含有这些玩意的直接不推送。

最后,重启 shell 或者 ( $ source ~/.bashrc 或者 $ source ~/.bash_profile )。

这一招在 Ubuntu 14.04 和 macOS 10.12.4 自带的 bash 上都能工作,若在你的平台上不能工作,请邮件留言。实际上这个脚本还是有些缺陷的,若你能改进这个脚本,也请邮件联系在下(谢谢你)。

此外在 zsh 上会更加简单,因为它自己就支持命令执行前后的回调函数。而不像这个 bash 的魔改脚本。

这个脚本参考自 DEBUG trap and PROMPT_COMMAND in Bash

social