Grep esce lentamente dopo aver trovato la corrispondenza?


20

Sto cercando di scrivere uno script bash che interroga btmon per le connessioni del dispositivo. Ho una soluzione funzionante, ma è assurdamente lento, e sembra che il problema sia che grep sia molto lento ad uscire dopo aver trovato una partita (circa 25 secondi). Cosa posso fare per accelerare grepo evitare di usarlo del tutto?

#!/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

modifica: per chiarire, btmoned è uno strumento di monitoraggio bluetooth che fa parte della suite Bluez, e cec-client è un'utilità che è impacchettata con libCEC per inviare comandi attraverso il bus seriale HDMI-CEC (tra le altre cose).


2
Quanta "roba" produce btmon? sei sicuro che non sia solo una questione di buffering?
steeldriver,

@steeldriver Seconded. Hai provato a disabilitare il buffering nella pipe?
l0b0,

btmon genera circa 250 caratteri al secondo.
Rob,

@ l0b0 Ho provato a disabilitare il buffering con il comando unbuffer, ma questo sembra impedire a grep di uscire? Ho anche provato a forzare grep in modalità --line-buffer, ma non mi è sembrato utile.
Rob,

Potrebbe essere che btmonimplementa il buffering stesso, nel qual caso sei sfortunato.
l0b0,

Risposte:


28

Nel:

cmd1 | cmd2

La maggior parte delle shell (la shell Bourne, (t) csh, così come yash e alcune versioni di AT&T ksh in alcune condizioni, essendo le notevoli eccezioni) attendono entrambe cmd1e cmd2.

In bash, lo noterai

sleep 1 | uname

ritorna dopo un secondo.

Nel:

btmon | grep -m 1 '@ Device Disconnected'

grepuscirà non appena viene rilevata un'occorrenza del modello, ma bashattenderà comunque btmon.

btmonin genere morirà di SIGPIPE la prossima volta che scrive sulla pipe dopo che grepè tornato, ma se non scrive mai più nulla, non riceverà mai quel segnale.

È possibile sostituire #! /bin/bashcon #! /bin/ksh93una shell compatibile con bashquella che attende solo l'ultimo componente di una pipeline. Quindi dentro

btmon | grep -m 1 '@ Device Disconnected'

dopo i grepritorni, btmonverrebbe lasciato in esecuzione in background e la shell continuerebbe con il resto dello script.

Se volessi uccidere btmonnon appena grepritorna, POSIXly, potresti fare qualcosa del tipo:

sh -c 'echo "$$"; exec btmon' | (
   read pid
   grep -m1 '@ Device Disconnected' || exit
   kill "$pid" 2> /dev/null
   true)

3
Grazie per aver spiegato perché questo si sta comportando in questo modo. Non mi è venuto in mente che Bash potrebbe essere in attesa dell'uscita di Bmon. Lo scambio con ksh93 funziona magnificamente!
Rob,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.