Bash脚本通过文件描述符解析UART客户端输出失败,求排查方案
分析你的UART客户端脚本问题
首先得指出你当前脚本里的核心错误:你用exec 3< ./uart_client是把uart_client这个可执行文件当作普通文本文件来打开读取,而不是执行它并捕获它的运行输出!这就导致你的while read循环一直在读uart_client程序本身的代码,而不是它启动时输出的日志,自然匹配不到你要的background或Cannot关键词,逻辑肯定走不对。
修正方案:正确捕获程序输出
方法1:用管道直接处理输出(最简单)
这是最直观的写法,直接把uart_client的输出通过管道传给while循环处理。如果程序有错误输出(stderr),记得加上2>&1把stderr合并到stdout,避免漏掉关键错误信息:
# 合并stdout和stderr,通过管道传给循环 stdbuf -oL ./uart_client 2>&1 | while read -r line; do case "$line" in *background*) echo "'$line' Done. creating connection" # 执行你的操作A break ;; *Cannot*) echo "'$line' no uart. Exiting loop" # 执行你的操作B break ;; *) echo "'$line'." ;; esac done
这里加了stdbuf -oL是为了强制程序输出为行缓冲模式——有些程序在非终端环境下会用全缓冲,导致输出不会实时刷新,read就没法及时读到内容,这个参数可以解决这个问题。
方法2:用文件描述符(符合你最初的思路)
如果你坚持想用文件描述符来实现,可以用进程替换<()来把uart_client的输出绑定到文件描述符,而不是直接读文件:
# 执行uart_client,将其输出(含stderr)绑定到fd3 exec 3< <(stdbuf -oL ./uart_client 2>&1) while read -r line <&3; do case "$line" in *background*) echo "'$line' Done. creating connection" # 操作A break ;; *Cannot*) echo "'$line' no uart. Exiting loop" # 操作B break ;; *) echo "'$line'." ;; esac done # 关闭文件描述符 exec 3<&- echo "done"
这个写法和你最初的思路一致,但用<(./uart_client 2>&1)代替了直接读文件,这样fd3读取的是uart_client运行时的输出,而不是程序文件本身。
额外注意事项
- 一定要用
read -r:避免read命令自动转义输入中的反斜杠,防止输出内容被篡改。 - 确认输出流:如果
uart_client的关键日志是输出到stderr(比如启动失败的提示),必须加2>&1才能捕获到。 - 缓冲问题:如果程序输出没有实时显示,
stdbuf -oL或unbuffer(需要安装expect包)可以强制行缓冲,确保read能及时拿到每一行输出。
内容的提问来源于stack exchange,提问作者me and stuff
相关产品推荐
相关产品推荐

