我正在尝试编写一个 BASH 脚本,每次在 dbus-monitor 的输出中找到某个字符串(稍后在帖子中指定的参数)时,该脚本都会创建一个时间戳(要写入文件)。我的脚本的主要目的是在 Spotify 上开始播放歌曲时节省时间(包括毫秒)和日期,因为它使用通知。
string "Spotify"
每当播放歌曲时,就会输出以下命令。
dbus-monitor --session interface='org.freedesktop.Notifications',member='Notify' | grep 'string "Spotify"'
我的尝试:
search='string "Spotify"'
found=$(dbus-monitor --session interface='org.freedesktop.Notifications',member='Notify' | grep 'string "Spotify"')
while [ ${search} == ${found} ]; do
date -u +%Y%M%d-%H%M%S.%N >> timestamp.txt
done
我假设代码功能障碍的原因是 dbus-monitor 持续运行,因此阻止了 while 循环的执行。
答案1
使用awk
而不是grep
- 类似:
dbus-monitor ... | awk '/Spotify/ {
system("date -u +%Y%m%d-%H%M%S.%N >> timestamp.txt")
}'
(注意使用%Y%m%d
代替%Y%M%D
- 大写-M 是分钟,而不是月。大写-D 相当于%m/%d/%y
)
每当在输入中看到“Spotify”时,这将使用 awk 的system()
函数在子 shell 中运行 date 命令。或者,使用 awk 的内置日期格式和重定向:
dbus-monitor ... | awk '/Spotify/ {
print strftime("%Y%m%d-%H%M%S") >> "timestamp.txt"
}'
此版本不会在时间戳中打印纳秒,因为strftime()
不支持%N
.
或者,使用 perl 而不是 awk。这将允许你使用perl的桌面::通知模块来获取通知或网络::DBus直接与dbus通信。
答案2
由于您有 GNU 实用程序,您可以执行以下操作:
dbus-monitor --session interface='org.freedesktop.Notifications',member='Notify' |
sed -un 's/^.*string "Spotify".*$/now/p' |
stdbuf -oL date -uf - +%Y%m%d-%H%M%S.%N >> timestamp.txt
dbus-monitor
已经禁用缓冲,所以stdbuf -oL
那里没有必要。
-u
GNU 的选项会sed
禁用输出缓冲,并使其在此处不可查找时一次读取一个字节的输入。我们不需要后者,但我们需要前者,以便它在读取时立即输出一行。
在这里,每次找到包含 的行时我们都会sed
输出。now
string "Spotify"
那now
是喂给date
.使用-f -
,从标准date
输入读取date
并打印。对于每个now
读取的内容,它都会以指定的格式打印当前时间。我们确保输出立即stdbuf -oL
进入文件而不是分块。timestamp.txt
如果您确实想运行任何任意命令,而不仅仅是使用 zsh/bash/ksh93 输出当前时间,您可以这样做:
while IFS= read -ru3 line || [ -n "$line" ]; do
any arbitrary command
done 3< <(
dbus-monitor --session interface='org.freedesktop.Notifications',member='Notify' |
grep --line-buffered 'string "Spotify"'
)
答案3
这应该有效:
stdbuf -oL dbus-monitor --session interface='org.freedesktop.Notifications',member='Notify' |
while grep -q 'string "Spotify"'; do
date -u +%Y%M%d-%H%M%S.%N >> timestamp.txt
done
在 @StéphaneChazelas 评论后编辑:
stdbuf -oL dbus-monitor --session interface='org.freedesktop.Notifications',member='Notify' |
grep --line-buffered 'string "Spotify"' |
while read trash; do
stdbuf -oL date -u +%Y%M%d-%H%M%S.%N >> timestamp.txt
done
+1 个其他答案,但为了完整性我保留这个答案
答案4
在这种情况下,它看起来dbus-monitor
已经提供了时间戳(以纪元时间+微秒为单位)。所以你可能不需要date
为每场比赛都执行。也许可以使用例如 来缩小匹配表达式的范围arg0='Spotify'
。
检查此输出:
dbus-monitor "
type='method_call',
interface='org.freedesktop.Notifications',
member='Notify',
arg0='Spotify'"
希望您只会看到与来自 Spotify 的通知相关的 dbus 消息(无法测试这一点 - 这只是通过查看总线规范)。如果这有效,那么以下可能是合适的:
dbus-monitor --profile "type='method_call',
interface='org.freedesktop.Notifications', member='Notify', arg0='Spotify'" |
gawk -F '\t' '
$NF=="Notify" {
secs = usecs = $2
sub(/^[^.]+/,"",usecs)
print strftime("%Y%m%d-%H%M%S",int(secs),"UTC") usecs
fflush()
}' > timestamp.log
用于--profile
输出格式,因为它似乎比默认输出更容易解析--monitor
。通过管道传输到 GNUawk
以提取并格式化时间戳。