Я использую это в сценарии.
echo $(echo "sign 00:07:32:46:04:75" | socat UDP4-DATAGRAM:239.192.0.2:9000 -)
но это немедленно останавливается и я не получаю ответа от сервера
если я сделаю
echo $(echo "sign 00:07:32:46:04:75" | socat -t5 UDP4-DATAGRAM:239.192.0.2:9000 -)
он всегда ждет 5 seconds
также, когда ответ будет доступен через 1 секунду.
Есть ли способ остановить команду сразу после получения первого сообщения?
решение1
Предполагая, что ответ представляет собой одну строку текста, разделенную символом новой строки, с помощью bash
, вы всегда можете сделать:
IFS= read -r answer < <(
echo 'sign 00:07:32:46:04:75' |
socat -t 5 - UDP4-DATAGRAM:239.192.0.2:9000)
Он вернется, как только поступит ответ, и socat
будет работать в фоновом режиме в течение оставшегося времени.
В zsh
, вам нужно добавить &
в конце конвейера, echo|socat
чтобы он не ждал его. Вы можете на самом деле захотеть добавить его bash
также, чтобы быть готовым к будущему, если bash
решит изменить поведение в будущем.
Если ответ может быть больше одной строки или не разделен новой строкой, zsh
можно сделать следующее:
zmodload zsh/system
(echo 'sign 00:07:32:46:04:75' |
socat -t 5 - UDP4-DATAGRAM:239.192.0.2:9000 &) | sysread answer
Встроенный sysread
делаетодин read()
системный вызов размером 8192. Это предполагает, что socat
ответ записывается в конвейер водин write()
системный вызов (что он и делает).
Для этого вы всегда можете прибегнуть к портативным средствам dd
:
answer=$(
(echo 'sign 00:07:32:46:04:75' |
socat -t 5 - UDP4-DATAGRAM:239.192.0.2:9000 &) |
dd bs=8192 count=1 2> /dev/null
)
(обратите внимание, что подстановка команды удаляет все конечные символы новой строки).
Если вы не хотите терять socat
времени еще несколько секунд после этого, вы можете сделать что-то вроде:
answer=$(
(echo 'sign 00:07:32:46:04:75' |
sh -c 'echo "$$"
exec socat -t 5 - UDP4-DATAGRAM:239.192.0.2:9000 &
) | {
IFS= read pid
dd bs=8192 count=1 2> /dev/null
kill -s PIPE "$pid"
}
)