Linux shell脚本在第一行后停止

3

我尝试基于MQTT主题执行etherwake命令。 如果将mosquitto_sub的输出通过管道传递到while语句中,则会停止输出。

可运行的示例:

# mosquitto_sub -L mqtt://... | grep -o -E '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}'
00:00:00:00:de:ad
00:00:00:00:be:ef
00:00:00:00:ca:fe
(goes on and on)

无法工作:

mosquitto_sub -L mqtt://... \
  | grep -o -E '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}' \
  | hexdump

输出在一行之后停止:

0000000 1234 5678 9abc def0 abcd cafe 3762 3a65

大局观是这样的:

mosquitto_sub -L mqtt://... \
  | grep -o -E '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}' \
  | while read macaddr; do
      echo "send WOL to " $macaddr;
      /usr/bin/etherwake -D -b "$macaddr" 2>&1;
    done

通常情况下我对Linux shell很熟悉,但这一次在第一行之后它变得卡住了。

我的猜测是stdin或stdout出现了问题(未被读取或已满等),但我想不出原因。

顺便说一句,这是一个OpenWRT shell,所以是ash而不是bash。


1
你是否考虑过这是否是缓冲问题?数据速率是多少?你是否等待足够长的时间,让grep的标准输出积累约4kb左右的内容,或者在它没有将期望的内容写入输出时就无限期地调用它? - Charles Duffy
2
如果这确实是问题的原因,那么最好将此问题标记为重复问题 https://dev59.com/bKrka4cB1Zd3GeqPdW7k - Charles Duffy
1
顺便提一下,可以查看 https://eklitzke.org/stdout-buffering 了解这种行为的原因。 - Charles Duffy
非常感谢大家,我认为你们都说到了点子上。不幸的是,OpenWRT没有未经缓冲的 'grep' 或 'sed' 版本。 - muebau
请注意,etherwake也在读取仅由read读取的管道。它可能会忽略该流并且不消耗任何数据,但请确保您真的需要执行while read macaddr; do ...; /usr/bin/etherwake -D -b "$macaddr" 2>&1 <&-; ...并关闭etherwake的stdin(或将其重定向从/dev/zero或/dev/null等)。 - William Pursell
可能是通过grep管道传递tail时没有输出的重复问题。 - Doug Richardson
1个回答

2

问题确实出在使用管道时grep的“缓冲”。

通常应使用“--line-buffered”开关来强制grep逐行处理数据,而不是缓冲数据。

由于OpenWRT(busybox)上的grep没有此开关,“awk”被使用:

最初的回答

mosquitto_sub -L mqtt://... \
  | awk '/([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}/{ print $0 }' \
  | hexdump

如果没有使用busybox版本的grep,则解决方案如下:

最初的回答:

mosquitto_sub -L mqtt://... \
  | grep -o --line-buffered -E '([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}' \
  | hexdump

非常感谢大家的帮助。

最初的回答:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接