Греп повільно вийти після пошуку матчу?


20

Я намагаюся написати скрипт bash, який опитує btmon для підключення пристроїв. У мене є робоче рішення, але це абсурдно повільно, і, схоже, проблема полягає в тому, що проблема є дуже повільною, щоб вийти після пошуку відповідності (близько 25 секунд). Що я можу зробити, щоб прискорити grepабо взагалі не використовувати його?

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

редагувати: Для уточнення, btmonце інструмент Bluetooth для моніторингу, який є частиною пакета Bluez, а cec-клієнт - це утиліта, яка постачається з libCEC для видачі команд через послідовну шину HDMI-CEC (серед іншого).


2
Скільки "штук" робить btmon? ви впевнені, що це не лише питання буферизації?
steeldriver

@steeldriver Відряджений. Ви намагалися відключити буферизацію в трубі?
l0b0

btmon видає близько 250 символів в секунду.
Роб

@ l0b0 Я спробував відключити буферизацію за допомогою команди unbuffer, але це, здається, взагалі не дозволяє grep виходити? Я також спробував примусити grep до --line-buffer mode, але це, здається, не допомогло.
Роб

Це може бути те, що btmonреалізує буферизацію себе, і в цьому випадку вам не пощастить.
l0b0

Відповіді:


28

В:

cmd1 | cmd2

Більшість оболонок (оболонка Борна, (t) csh, а також яш та деякі версії AT&T ksh за деяких умов, що є помітними винятками) чекають і обох, cmd1і cmd2.

В bash, ви помітите , що

sleep 1 | uname

повертається через одну секунду.

В:

btmon | grep -m 1 '@ Device Disconnected'

grepвийде, як тільки знайде одну появу шаблону, але bashвсе одно чекатиме btmon.

btmonзазвичай загине від SIGPIPE наступного разу, коли він запише в трубу після того, grepяк повернеться, але якщо він ніколи нічого більше не запише, він ніколи не отримає цей сигнал.

Ви могли б замінити #! /bin/bashз , #! /bin/ksh93як це оболонка сумісна з bashі один , який чекає тільки для останнього компонента трубопроводу. Тоді в

btmon | grep -m 1 '@ Device Disconnected'

після grepповернення btmonзалишиться працювати у фоновому режимі, а оболонка продовжуватиметься з рештою сценарію.

Якщо ви хочете вбити, btmonяк тільки grepповернеться, POSIXly, ви можете зробити щось на кшталт:

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

3
Дякую за пояснення, чому це поводиться так, як це відбувається. Мені не прийшло в голову, що баш може чекати виходу btmon. Заміна на ksh93 працює прекрасно!
Роб
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.