我使用的是 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
监控程序的对话并发送警报
您可以监控以下活动
- A先进先出或者
- 一个
xterm
日志档案,现在有交互模式
并让它开始zenity
信息消息,当有来自受监控程序的输入时。如果您愿意,还可以安装espeak
并让它发送一个音频消息。
zenity
1.当使用 fifo 的受监控程序有输入时,启动信息消息。
以下 shellscript 可以监视程序的输出对话并发送警报。
- 假设图形桌面环境
- 在终端窗口中启动一个包装器 shellscript,它的用途就像“控制台”一样
wrapper
xterm
在窗口中启动要监控的程序xterm
在窗口中运行对话(这是你写输入的地方)- 使用 fifo 来访问要监视的程序的输出,
/dev/stdout
以及dev/stderr
. - 运行一个
while
循环- 测试 fifo 是否已被修改,在这种情况下
- 启动
zenity
信息消息窗口。
- 启动
- 测试 fifo 是否已被修改,在这种情况下
您需要关闭该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"
您可能也希望跑espeak
近zenity
以获取音频消息。在这种情况下,您可以删除#
该行开头的字符。 (程序中可能有很多文本,因此将 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
zenity
2.当某些内容写入窗口时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。我会听取反馈并专注于首选脚本/方法,并尝试将首选脚本/方法合并到一个答案中(除非有理由保留所有这些脚本/方法(出于不同目的)。
监控程序的对话并发送警报
您可以监控以下活动
- A先进先出或者
- 一个
xterm
日志档案
并让它开始zenity
信息消息,当有来自受监控程序的输入时。如果您愿意,还可以安装espeak
并让它发送一个音频消息。
这个答案重点关注第二种选择,使用先进先出。
zenity
当使用 fifo 的受监控程序有输入时,启动信息消息。
1.1 使用xterm
,通过fifo监控标准输出和标准错误
该wrapper
方法具有
- 优势,任何直接输入都不会触发警报。这适用于许多程序,例如
cp -i
和sudo
。 - 坏处, 那
- 某些程序将被禁用,因为它们不仅使用标准输出和标准错误来写入其输出。示例:
sftp
将丢失提示,用户无法知道程序何时准备好执行新任务。 - 有些程序回显输入(存在间接输入),这将触发警报,这可能会导致 shell 脚本中出现大量警报,而这些警报没有考虑到这一点。例子:
ssh
。
- 某些程序将被禁用,因为它们不仅使用标准输出和标准错误来写入其输出。示例:
script
1.2通过 fifo使用编译后的程序及其日志文件
以下 shellscript 可以监视程序的输出对话并发送警报。它需要espeak
和script
(script
在 Ubuntu 和 Debian 中不需要安装)。
sudo apt update
sudo apt install espeak
- 假设图形桌面环境
- 在终端窗口中启动一个 shellscript,让我们调用它
viafifo
。 - 启动要监视的程序“in
viafifo
” - 在终端窗口中运行对话(这是你写输入的地方)
- 使用 fifo 来访问要监视的程序的输出
/dev/stdin
,/dev/stdout
和dev/stderr
。 shellscript中的主要任务是与程序的行script
,即监视终端窗口中的活动并写入 fifo。 - 运行一个
while
循环- 测试 fifo 是否已被修改,在这种情况下
- 启动
zenity
信息消息窗口和相应的语音消息espeak
。 - 输入时允许短暂延迟(8 秒;您可以编辑脚本文件来更改延迟时间)。
- 启动
- 测试 fifo 是否已被修改,在这种情况下
您需要关闭该zenity
窗口(可以使用“Enter”键)以返回到xterm
输入内容的窗口。
键入exit
离开script
和viafifo
。之后,您可以获得包含整个对话的日志文件。
viafifo
经测试
- 乌班图18.04.1 长期支持。<---你找到了bash代码的
viafifo
在这个链接。 - 德班9.6.0,“拉伸”。请参阅以下屏幕截图和打印输出
time viafifo
和viafifo.log
。
演示示例
截图
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:~$