Grep lento para salir después de encontrar partido?

20

Estoy tratando de escribir un script bash que sondee btmon para las conexiones del dispositivo. Tengo una solución que funciona, pero es absurdamente lenta, y parece que el problema es que grep es muy lento para salir después de encontrar una coincidencia (alrededor de 25 segundos). ¿Qué puedo hacer para acelerar grepo evitar usarlo por completo?

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

editar: para aclarar, btmony es una herramienta de monitoreo de bluetooth que es parte de la suite Bluez, y cec-client es una utilidad que está empaquetada con libCEC para emitir comandos a través del bus serie HDMI-CEC (entre otras cosas).

Robar
fuente
2
¿Cuánto "material" produce btmon? ¿estás seguro de que no es solo una cuestión de almacenamiento en búfer?
steeldriver
@steeldriver Secundado. ¿Has intentado deshabilitar el almacenamiento en búfer en la tubería?
l0b0
btmon genera alrededor de 250 caracteres por segundo.
Rob
@ l0b0 ¿Intenté deshabilitar el almacenamiento en búfer con el comando unbuffer, pero eso parece evitar que grep salga? También intenté forzar grep al modo --line-buffer, pero eso no pareció ayudar.
Rob
Podría ser que btmonimplementa el almacenamiento en búfer, en cuyo caso no tiene suerte.
l0b0

Respuestas:

28

En:

cmd1 | cmd2

La mayoría de los shells (el shell Bourne, (t) csh, así como el yash y algunas versiones de AT&T ksh en algunas condiciones son las excepciones notables) esperan ambos cmd1y cmd2.

En bash , notarás que

sleep 1 | uname

regresa después de un segundo.

En:

btmon | grep -m 1 '@ Device Disconnected'

grep saldrá tan pronto como haya encontrado una aparición del patrón, pero bash aún esperará btmon.

btmon normalmente morirá de un SIGPIPE la próxima vez que escriba en la tubería después de grep haya regresado, pero si nunca vuelve a escribir nada, nunca recibirá esa señal.

Se podría sustituir a #! /bin/bashla #! /bin/ksh93ya que es una cáscara compatible con bashy que sólo espera a que el último componente de un oleoducto. Entonces en

btmon | grep -m 1 '@ Device Disconnected'

después grep retornos, btmonse dejaría ejecutándose en segundo plano y el shell continuaría con el resto del script.

Si quisieras matar btmontan pronto como grepregrese, POSIXly, podrías hacer algo como:

sh -c 'echo "$$"; exec btmon' | (
   read pid
   grep -m1 '@ Device Disconnected' || exit
   kill "$pid" 2> /dev/null
   true)
Stéphane Chazelas
fuente
3
Gracias por explicar por qué esto se comporta como lo hace. No se me ocurrió que bash podría estar esperando a que btmon salga. ¡Cambiar a ksh93 funciona de maravilla!
Rob