正規表現が一致するたびにコマンドを実行し、EOFなしでstdinから読み込みます。

正規表現が一致するたびにコマンドを実行し、EOFなしでstdinから読み込みます。

dbus-monitorの出力で特定の文字列が見つかるたびにタイムスタンプ(ファイルに書き込まれる)を生成するBASHスクリプトを作成しようとしています(パラメータは後で指定します)。私のスクリプトの主な目的は、通知を使用するため、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")
  }'

(月以外の間、-Mの%Y%m%d代わりに大文字Mが使用されます。CAPS-Dは同じです。)%Y%M%D%m/%d/%y

これは、入力に「Spotify」が表示されるたびに、awkのsystem()機能を使用してサブシェルでdateコマンドを実行します。または、awkに組み込まれている日付形式とリダイレクトを使用してください。

dbus-monitor ... | awk '/Spotify/ {
    print strftime("%Y%m%d-%H%M%S") >> "timestamp.txt"
  }'

strftime()このバージョンはサポートされていないため、タイムスタンプにナノ秒を印刷しません%N

または、awkの代わりにperlを使用してください。これによりPerlを使用できます。デスクトップ::通知通知を受け取るためのモジュールまたはネットワーク::DBusdbusと直接通信してください。

答え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そこには必要ありません。

-uGNUのオプションはsed出力バッファリングを無効にし、ここで取得できない場合は入力を一度に1バイトずつ読み取るようにします。後者は必要ありませんが、読むとすぐに1行を出力するには前者が必要です。

ここでは、sed含まれている行が見つかるたびに印刷します。nowstring "Spotify"

それは標準入力から読み取って印刷する Feed.usenowです。各読み取りごとに現在時刻を指定された形式で印刷します。出力がチャンク単位ではなくすぐにファイルに入ることを保証します。date-f -datedatenowstdbuf -oLtimestamp.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。タイムスタンプを抽出してフォーマットするには、GNUにパイプしますawk

関連情報