Grep медленно завершает работу после нахождения совпадения?

Grep медленно завершает работу после нахождения совпадения?

Я пытаюсь написать скрипт bash, который опрашивает btmon на предмет подключений устройств. У меня есть работающее решение, но оно абсурдно медленное, и похоже, что проблема в том, что grep очень медленно завершает работу после нахождения совпадения (около 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

edit: Для ясности, btmonand — это инструмент мониторинга Bluetooth, входящий в пакет Bluez, а cec-client — это утилита, которая упакована с libCEC для выдачи команд по последовательной шине HDMI-CEC (помимо прочего).

решение1

В:

cmd1 | cmd2

Большинство оболочек (Bourne shell, (t)csh, а также yash и некоторые версии 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)

Связанный контент