Grep langsam zu beenden, nachdem das Spiel gefunden?

20

Ich versuche, ein Bash-Skript zu schreiben, das btmon nach Geräteverbindungen abfragt. Ich habe eine funktionierende Lösung, aber sie ist absurd langsam, und es scheint, als ob das Problem darin besteht, dass grep nach der Suche nach einer Übereinstimmung nur sehr langsam beendet wird (ungefähr 25 Sekunden). Was kann ich tun, grepum die Nutzung zu beschleunigen oder ganz zu vermeiden?

#!/bin/bash
COUNTER=0
while :
  do
    until btmon | grep -m 1 '@ Device Connected'
      do :
    done
    let COUNTER=COUNTER+1
    echo on 0 | cec-client RPI -s -d 1
    sleep 5
    echo as | cec-client RPI -s -d 1
    until btmon | grep -m 1 '@ Device Disconnected'
      do :
    done
    let COUNTER=COUNTER-1
    if [ $COUNTER -eq 0 ];
      then echo standby 0 | cec-client RPI -s -d 1;
    fi
done

Bearbeiten: Zur Verdeutlichung: Es btmonhandelt sich um ein Bluetooth-Überwachungstool, das Teil der Bluez-Suite ist, und cec-client ist ein mit libCEC gepacktes Dienstprogramm, mit dem Befehle (unter anderem) über den seriellen HDMI-CEC-Bus ausgegeben werden können.

rauben
quelle
2
Wie viel "Zeug" wird btmonausgegeben? Sind Sie sicher, dass es nicht nur um das Puffern geht?
Steeldriver
@steeldriver Abgeordnet. Haben Sie versucht, die Pufferung in der Pipe zu deaktivieren ?
10.
btmon gibt ungefähr 250 Zeichen pro Sekunde aus.
Rob
@ l0b0 Ich habe versucht, die Pufferung mit dem Unbuffer-Befehl zu deaktivieren, aber das scheint zu verhindern, dass grep überhaupt beendet wird. Ich habe auch versucht, grep zum --line-buffer-Modus zu zwingen, aber das schien nicht zu helfen.
Rob
Es könnte sein, dass sich btmonGeräte selbst puffern, in welchem ​​Fall Sie kein Glück haben.
10.

Antworten:

28

Im:

cmd1 | cmd2

Die meisten Shells (die Bourne-Shell (t) csh sowie yash und einige Versionen von AT & T ksh, die unter bestimmten Bedingungen die bemerkenswerten Ausnahmen darstellen) warten auf beide cmd1undcmd2 .

In bashwirst du das bemerken

sleep 1 | uname

kehrt nach einer Sekunde zurück.

Im:

btmon | grep -m 1 '@ Device Disconnected'

grepwird beendet, sobald es ein Vorkommen des Musters gefunden hat, bashwartet aber noch btmon.

btmonstirbt normalerweise an einem Sigpipe grep, wenn es das nächste Mal in die Pipe schreibt, nachdem es zurückgekehrt ist. Wenn es jedoch nie wieder etwas schreibt, wird es dieses Signal niemals empfangen.

Sie könnten ersetzen #! /bin/bashdurch, #! /bin/ksh93da dies eine Shell ist, die mit kompatibel ist, bashund eine, die nur auf die letzte Komponente einer Pipeline wartet. Dann in

btmon | grep -m 1 '@ Device Disconnected'

nach greprückkehr,btmon es im Hintergrund ausgeführt, und die Shell setzt den Rest des Skripts fort.

Wenn Sie POSIXly btmonsofort nach der grepRückkehr töten möchten, können Sie Folgendes tun:

sh -c 'echo "$$"; exec btmon' | (
   read pid
   grep -m1 '@ Device Disconnected' || exit
   kill "$pid" 2> /dev/null
   true)
Stéphane Chazelas
quelle
3
Vielen Dank für die Erklärung, warum sich das so verhält. Es ist mir nicht in den Sinn gekommen, dass Bash möglicherweise darauf wartet, dass Btmon beendet wird. Das Wechseln zu ksh93 funktioniert wunderbar!
Rob