监控程序的对话并发送警报

监控程序的对话并发送警报

我使用的是 Ubuntu 16.04 LTS。我的中有一个别名,.bashrc它使用notify-send

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

我可以将alert其他命令附加为somecommand; alert或,并在完成(成功)somecommand && alert后获得弹出通知。somecommand它提醒我,我在终端窗口(现已最小化)或在不同工作区中运行的命令已完成执行。

但当它等待用户输入而不是完成时(例如是/否提示),我想要一个类似的警报。我怎样才能做到这一点?

使用类似的解决方案notify-send会很棒,但其他比较简单替代方案也很好。

为了防止出现混乱,我不打算创建对提示的自动回复。我只是想让它提醒我在运行具有冗长输出的命令时忘记(最小化/在不同工作区中)终端窗口,这可能会要求用户输入(例如apt update && apt upgrade)。

答案1

监控程序的对话并发送警报

您可以监控以下活动

  1. A先进先出或者
  2. 一个xterm日志档案,现在有交互模式

并让它开始zenity信息消息,当有来自受监控程序的输入时。如果您愿意,还可以安装espeak并让它发送一个音频消息

zenity1.当使用 fifo 的受监控程序有输入时,启动信息消息。

以下 shellscript 可以监视程序的输出对话并发送警报。

  • 假设图形桌面环境
  • 在终端窗口中启动一个包装器 shellscript,它的用途就像“控制台”一样wrapper
  • xterm在窗口中启动要监控的程序
  • xterm在窗口中运行对话(这是你写输入的地方)
  • 使用 fifo 来访问要监视的程序的输出,/dev/stdout以及dev/stderr.
  • 运行一个while循环
    • 测试 fifo 是否已被修改,在这种情况下
      • 启动zenity信息消息窗口。

您需要关闭该zenity窗口(可以使用“Enter”键)以返回到xterm输入内容的窗口。

#!/bin/bash

if [ $# -eq 0 ]
then
 echo "'$0' is a wrapper, that sends a notification, when the wrapped program
has written to standard input and standard error and may be waiting for input.
---
Usage:   $0 <program name> [parameters]
Example: $0 .program"
 exit
fi

message="'${1##*/} $2 ...' has written something, maybe asks for input"

tmpdir=$(mktemp -d)
tmpfifo=$(mktemp --tmpdir=$tmpdir)
rm "$tmpfifo"
mkfifo "$tmpfifo"
#ls -l "$tmpdir"
cnt1=$(stat --printf "%Y" "$tmpfifo")
sleep 1

xterm -title "${1##*/} $2 ..." -fa default -fs 11 -bg '#403600' \
 -e bash -c "$* 2>&1 | tee /dev/stderr 2>&1 > $tmpfifo" 2> /dev/null & pid=$!

#< "$tmpfifo" espeak &
< "$tmpfifo" cat &

cont=true
while $cont
do
 tmpstr=$(ps -Af |sed "s/grep $pid//"|grep "$pid")
# echo "$tmpstr"
 if [ "$tmpstr" != "" ]
 then
  cnt0=$cnt1
  cnt1=$(stat --printf "%Y" "$tmpfifo")
  if [ "$cnt1" != "$cnt0" ]
  then
#   zenity --notification --text="$message" 2> /dev/null
#   espeak "$message" &
   zenity --info --title="${0##*/} ${1##*/} $2 ..." \
    --text="$message" --width=500  2> /dev/null
  fi
  sleep 1
  else
  sleep .2
  # echo "process $pid has finished"
  cont=false
 fi
done

# clean up

rm -r "$tmpdir"

您可能也希望跑espeakzenity以获取音频消息。在这种情况下,您可以删除#该行开头的字符。 (程序中可能有很多文本,因此将 fifo 重定向到 通常不是一个好主意espeak。最好将 fifo 重定向到cat并将其打印在“控制台”中。)

演示

cp -i您可以使用和测试一些命令行,mv -i并且可以使用以下小 shellscript 进行测试program

#!/bin/bash

while true
do
 read -p "Waiting for input. 'Stop' to Quit " string
 if [ "${string:0:4}" == "Stop" ]
 then
  printf "$string. Gotcha\n"
  break
 elif [ "$string" != "" ]
 then
  printf "$string\n"
  printf "Working for 10 seconds ...\n"
  sleep 10
 else 
  sleep 3
 fi
done

帮助文本:

$ ./wrapper
'./wrapper' is a wrapper, that sends a notification, when the wrapped program
has written to standard input and standard error and may be waiting for input.
---
Usage:   ./wrapper <program name> [parameters]
Example: ./wrapper .program

监控program

$ ./wrapper ./program

zenity信息消息窗口:

在此输入图像描述

窗口对话xterm

Waiting for input. 'Stop' to Quit Hello
Hello
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit World
World
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Goodbye
Goodbye
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Stop

完成后在原始终端窗口中的“控制台”输出:

$ ./wrapper ./program
Waiting for input. 'Stop' to Quit Hello
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit World
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Goodbye
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Stop. Gotcha

监控cp -ip

$ LANG=C /path/wrapper cp -ip ubuntustudio-18.04-dvd-amd64.iso ubuntu-18.04.1-desktop-amd64.iso /tmp

zenity信息消息窗口:

在此输入图像描述

对话xterm

cp: overwrite '/tmp/ubuntustudio-18.04-dvd-amd64.iso'? y
cp: overwrite '/tmp/ubuntu-18.04.1-desktop-amd64.iso'? n

监控sudo parted /dev/sdc

$ LANG=C ./wrapper sudo parted /dev/sdc

对话xterm

[sudo] password for sudodus: 
GNU Parted 3.2
Using /dev/sdc
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p                                                                
Model: SanDisk Extreme (scsi)
Disk /dev/sdc: 16,0GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type      File system  Flags
 3      2097kB  258MB   256MB   primary   fat32        boot
 4      258MB   1366MB  1108MB  primary
 2      1366MB  12,4GB  11,0GB  extended               lba
 5      1367MB  6736MB  5369MB  logical   ext2
 6      6737MB  12,4GB  5615MB  logical   ext4
 1      12,4GB  16,0GB  3662MB  primary   ntfs

(parted) q

zenity2.当某些内容写入窗口时xterm(从受监视的程序或从用户),启动信息消息。

以下 shellscript 可以监视与程序的对话并发送警报。

  • 假设图形桌面环境
  • 在终端窗口中启动一个包装器 shellscript,它的用途就像“控制台”一样wrapper
  • xterm在窗口中启动要监控的程序
  • xterm在窗口中运行对话(这是你写输入的地方)
  • 使用日志文件来xterm访问要监视的程序的输出和输入
  • 运行一个while循环
    • 测试日志文件是否已被修改,在这种情况下
      • 启动zenity信息消息窗口。
      • 输入时允许短暂延迟(8 秒;您可以编辑脚本文件来更改延迟时间)。

您需要关闭该zenity窗口(可以使用“Enter”键)以返回到xterm输入内容的窗口。

现在有一种交互模式,您xterm可以像使用任何终端窗口一样使用该窗口。关闭xterm窗口即可停止监视。

#!/bin/bash

# date        editor   comment
# 2018-12-31  sudodus  version 1.0

version=1.0

name="${0##*/}"
if [ "$1" == "-h" ] || [ "$1" == "--help" ]
then
 echo "'$name' is a wrapper, that sends a notification, when the wrapped program
has written to standard input and standard error and may be waiting for input.
---
Usage:    $name [program name] [parameters]
Examples: $name          # to run program(s) interactively in an xterm window
          $name program
          $name -h       # to get help (this text)
          $name -v       # show version"
 exit
elif [ "$1" == "-v" ]
then
 echo "$name version $version"
 exit
fi
tstart=$(date '+%s')
echo "----- start $name at $(date '+%F %T') ----------------------------"
tmpstr="${1##*/}"
xtermlog=$(mktemp -u)

if [ $# -eq 0 ]
then
 mess_zenity="Check, if the monitored program asks for input"
 mess_espeak="${mess_zenity/program/, Program,}"
 xterm -title "monitored by ${0##*/}" -fa default -fs 11 -bg '#2c2b2a' \
 -l -lf "$xtermlog" -sb -rightbar 2> /dev/null & pid=$!
else
 mess_espeak="Check if '${tmpstr^} ${2##*/} ${3##*/} ...' asks for input"
 mess_zenity="Check if '$tmpstr $2 $3 ...' asks for input"
 xterm -title "${1##*/} $2 $3 ..." -fa default -fs 11 -bg '#2c2b2a' \
 -l -lf "$xtermlog" -e "$@" 2> /dev/null & pid=$!
fi
sleep 0.5
sync
cnt1=$(stat --printf "%Y" "$xtermlog")
tail -f "$xtermlog" & ptail=$!

cont=true
while $cont
do
 sleep 1
 cnt0=$cnt1
 tmpstr=$(ps -Af |sed "s/grep $pid//"|grep "$pid")
# echo "$tmpstr"
 if [ "$tmpstr" != "" ]
 then
  cnt1=$(stat --printf "%Y" "$xtermlog")
  if [ $cnt1 -gt $((cnt0 + 8)) ]
  then
#   zenity --notification --text="$message" 2> /dev/null
   espeak "$mess_espeak" &
   zenity --info --title="${0##*/} ${1##*/} $2 ..." \
    --text="$mess_zenity" --width=500  2> /dev/null
   touch "$xtermlog"
   cnt1=$(stat --printf "%Y" "$xtermlog")
  fi
  sleep 1
  else
  sleep .2
  # echo "process $pid has finished"
  cont=false
 fi
done

# clean up
tmpstr="$(tail -n1 "$xtermlog" | sed 's/.*exit.*/exit/')"
if [ "$tmpstr" != "exit" ]
then
 echo ""
fi
rm -r "$xtermlog"
kill $ptail
tend=$(date '+%s')
tuse=$((tend-tstart))
echo "------- end $name at $(date '+%F %T') --- used $tuse seconds"

将此bash代码保存到文件中,并为其指定名称(例如)vialog,使其可执行,或者将其移动到路径中的目录中。

$ vialog
----- start vialog at 2018-12-31 14:37:41 ----------------------------

您在xterm窗口中工作,对话也会回响到起始窗口。

在此输入图像描述

sudodus@bionic64 /media/multimed-2/test/test0/pomsky-wrap $ ./program
Waiting for input. 'Stop' to Quit Hello World
Hello World
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit I am writing ...
I am writing ...
Working for 10 seconds ...
Waiting for input. 'Stop' to Quit Stop
Stop. Gotcha
sudodus@bionic64 /media/multimed-2/test/test0/pomsky-wrap $ scrot -sb
sudodus@bionic64 /media/multimed-2/test/test0/pomsky-wrap $ exit
exit
------- end vialog at 2018-12-31 14:39:02 --- used 81 seconds

在此输入图像描述

答案2

邀请反馈

我认为最好使用第二个答案,而不是在已有的答案中添加另一个 shellscript。我会听取反馈并专注于首选脚本/方法,并尝试将首选脚本/方法合并到一个答案中(除非有理由保留所有这些脚本/方法(出于不同目的)。

监控程序的对话并发送警报

您可以监控以下活动

  1. A先进先出或者
  2. 一个xterm日志档案

并让它开始zenity信息消息,当有来自受监控程序的输入时。如果您愿意,还可以安装espeak并让它发送一个音频消息

这个答案重点关注第二种选择,使用先进先出

zenity当使用 fifo 的受监控程序有输入时,启动信息消息。

1.1 使用xterm,通过fifo监控标准输出和标准错误

wrapper方法具有

  • 优势,任何直接输入都不会触发警报。这适用于许多程序,例如cp -isudo
  • 坏处, 那
    • 某些程序将被禁用,因为它们不仅使用标准输出和标准错误来写入其输出。示例:sftp将丢失提示,用户无法知道程序何时准备好执行新任务。
    • 有些程序回显输入(存在间接输入),这将触发警报,这可能会导致 shell 脚本中出现大量警报,而这些警报没有考虑到这一点。例子:ssh

script1.2通过 fifo使用编译后的程序及其日志文件

以下 shellscript 可以监视程序的输出对话并发送警报。它需要espeakscriptscript在 Ubuntu 和 Debian 中不需要安装)。

sudo apt update
sudo apt install espeak
  • 假设图形桌面环境
  • 在终端窗口中启动一个 shellscript,让我们调用它viafifo
  • 启动要监视的程序“in viafifo
  • 在终端窗口中运行对话(这是你写输入的地方)
  • 使用 fifo 来访问要监视的程序的输出/dev/stdin/dev/stdoutdev/stderr。 shellscript中的主要任务是与程序的行script,即监视终端窗口中的活动并写入 fifo。
  • 运行一个while循环
    • 测试 fifo 是否已被修改,在这种情况下
      • 启动zenity信息消息窗口和相应的语音消息espeak
      • 输入时允许短暂延迟(8 秒;您可以编辑脚本文件来更改延迟时间)。

您需要关闭该zenity窗口(可以使用“Enter”键)以返回到xterm输入内容的窗口。

键入exit离开scriptviafifo。之后,您可以获得包含整个对话的日志文件。

viafifo经测试

演示示例

截图

在此输入图像描述

在此输入图像描述

time viafifo

user@debian:~$ time viafifo
----- Start viafifo ------------------------------------------------------------
user@debian:~$ echo hello
hello
user@debian:~$ exit
exit
----- End viafifo --------------------------------------------------------------
See 'viafifo.log'
viafifo used 8 seconds plus a few (5-10) seconds for preparing and finishing
real    0m13.295s
user    0m0.104s
sys 0m0.012s

viafifo.log

user@debian:~$ cat viafifo.log
Script started on Sat 05 Jan 2019 07:57:45 PM UTC
user@debian:~$ echo hello
hello
user@debian:~$ exit
exit
viafifo used 8 seconds
user@debian:~$ 

相关内容