Grep lento para sair depois de encontrar o jogo?


20

Estou tentando escrever um script bash que pesquisa btmon para conexões de dispositivos. Eu tenho uma solução funcional, mas é absurdamente lenta, e parece que o problema é grep, sendo muito lento para sair depois de encontrar uma correspondência (cerca de 25 segundos). O que posso fazer para acelerar grepou evitar o uso 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 esclarecer, btmone é uma ferramenta de monitoramento bluetooth que faz parte do pacote Bluez, e cec-client é um utilitário que acompanha o libCEC para emitir comandos através do barramento serial HDMI-CEC (entre outras coisas).


2
Quanto "material" produz btmon? Tem certeza de que não é apenas uma questão de buffer?
steeldriver

@steeldriver Seconded. Você já tentou desativar o buffer no pipe?
L0b0 23/05

btmon produz cerca de 250 caracteres por segundo.
Rob

@ l0b0 Tentei desabilitar o buffer com o comando unbuffer, mas isso parece impedir que o grep saia? Também tentei forçar o grep para o modo --line-buffer, mas isso não pareceu ajudar.
Rob

Pode ser que os btmonimplementos sejam armazenados em buffer; nesse caso, você está sem sorte.
L0b0 23/05

Respostas:


28

Em:

cmd1 | cmd2

A maioria dos shells (o shell Bourne, (t) csh, assim como o yash e algumas versões do AT&T ksh sob algumas condições, sendo as notáveis ​​exceções) esperam por ambos cmd1e cmd2.

Em bash, você notará que

sleep 1 | uname

retorna após um segundo.

Em:

btmon | grep -m 1 '@ Device Disconnected'

grepsairá assim que encontrar uma ocorrência do padrão, mas bashainda esperará btmon.

btmonnormalmente morrerá de um SIGPIPE na próxima vez que gravar no canal após grepretornar, mas se ele nunca gravar nada novamente, nunca receberá esse sinal.

Você poderia substituir #! /bin/bashcom #! /bin/ksh93como isso é uma shell compatível com bashe uma que só aguarda o último componente de um pipeline. Então em

btmon | grep -m 1 '@ Device Disconnected'

após grepretornos, btmonseria executado em segundo plano e o shell continuaria com o restante do script.

Se você quiser matar btmonassim que grepretornar, POSIXly, você pode fazer algo como:

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

3
Obrigado por explicar por que isso está se comportando dessa maneira. Não me ocorreu que o bash estivesse esperando o btmon sair. Trocar para ksh93 funciona lindamente!
Rob
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.