每次匹配正則表達式時執行命令,從沒有 EOF 的標準輸入讀取
我正在嘗試編寫一個 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 循環執行。
使用
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
)這將使用 awk 的
system()
函式在輸入中看到“Spotify”時在子 shell 中執行 date 命令。或者,使用 awk 的內置日期格式和重定向:dbus-monitor ... | awk '/Spotify/ { print strftime("%Y%m%d-%H%M%S") >> "timestamp.txt" }'
此版本不會在時間戳中列印納秒,因為
strftime()
不支持%N
.或者,使用 perl 而不是 awk。這將允許您使用 perl 的Desktop::Notify模組來獲取通知或Net::DBus直接與 dbus 通信。
由於您有 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"' )