Bash - 同时读取文件描述符
Bash - Reading from file descriptor simultaneously
我目前正在使用 Linux 文件描述符通过串行端口与外部设备通信,我想知道是否可以复制返回设备的结果。
具体来说,我在raspbian设备中使用5号文件描述符读写串口/dev/ttyACM0。
exec 5<>"/dev/ttyACM0"
在后台,我 运行 一个函数,只要有响应就可以连续读取端口以决定下一步。
function __processing__(){
local line
while read line<&5; do
... some processing ...
... echo $line > "log.txt"
done
}
如果我只是向串口发送单个命令并让后台函数处理响应,它一直工作正常。当我开始使用其他软件在前台使用 XMODEM 协议传输数据时,问题就出现了。
sx -vv -k "./firmware_update.bin" >&5 <&5
尽管日志文件中记录了 ACK 响应,但该进程一直在 ACK 上超时。所以我怀疑是因为后台进程从FD5读取,什么都没留下sx
。然后我尝试删除后台进程和运行只有sx
命令,当它成功发送所有数据包时证实了我的怀疑。
但是我没有任何来自串口的响应记录,所以我不知道下一步该做什么。
所以我的问题是:有没有办法重写后台函数,使其仍然可以读取响应,而不干扰sx
?我知道我们可以使用 tee
命令从 stdout 复制数据,我可以用 FD5 实现类似的东西吗?
提前谢谢大家。
尝试
sx -vv -k "./firmware_update.bin" >&5 < <(__processing__)
使用 Bash 进程替换(参见 ProcessSubstitution - Greg's Wiki)使 sx
从 __processing__
函数的输出中获取输入。您还需要修改函数以将其输入(从 FD5)复制到其标准输出。大致如下:
function __processing__
{
local line
while IFS= read -r line<&5; do
# ... some processing ...
printf '%s\n' "$line" > "log.txt"
printf '%s\n' "$line" # Copy input to standard output
done
}
- 该代码 Shellcheck-干净。
- 有关我在
while ...
行所做更改的解释,请参阅函数 BashFAQ/001 (How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?)。
- 请参阅对 Why is printf better than echo? 的已接受且优秀的回答,以了解为什么我将
echo
替换为 printf
。
- 请注意,即使我做了一些更改,如果来自 FD5 的数据是二进制的,
__processing__
函数也不会可靠地工作。 ASCII NUL 字符将丢失(Bash 字符串不能包含它们),这取决于以换行符终止的输入块。我不知道你在这种情况下处理的是哪种数据。它可能不是 Bash 代码可以处理的东西。
我目前正在使用 Linux 文件描述符通过串行端口与外部设备通信,我想知道是否可以复制返回设备的结果。
具体来说,我在raspbian设备中使用5号文件描述符读写串口/dev/ttyACM0。
exec 5<>"/dev/ttyACM0"
在后台,我 运行 一个函数,只要有响应就可以连续读取端口以决定下一步。
function __processing__(){
local line
while read line<&5; do
... some processing ...
... echo $line > "log.txt"
done
}
如果我只是向串口发送单个命令并让后台函数处理响应,它一直工作正常。当我开始使用其他软件在前台使用 XMODEM 协议传输数据时,问题就出现了。
sx -vv -k "./firmware_update.bin" >&5 <&5
尽管日志文件中记录了 ACK 响应,但该进程一直在 ACK 上超时。所以我怀疑是因为后台进程从FD5读取,什么都没留下sx
。然后我尝试删除后台进程和运行只有sx
命令,当它成功发送所有数据包时证实了我的怀疑。
但是我没有任何来自串口的响应记录,所以我不知道下一步该做什么。
所以我的问题是:有没有办法重写后台函数,使其仍然可以读取响应,而不干扰sx
?我知道我们可以使用 tee
命令从 stdout 复制数据,我可以用 FD5 实现类似的东西吗?
提前谢谢大家。
尝试
sx -vv -k "./firmware_update.bin" >&5 < <(__processing__)
使用 Bash 进程替换(参见 ProcessSubstitution - Greg's Wiki)使 sx
从 __processing__
函数的输出中获取输入。您还需要修改函数以将其输入(从 FD5)复制到其标准输出。大致如下:
function __processing__
{
local line
while IFS= read -r line<&5; do
# ... some processing ...
printf '%s\n' "$line" > "log.txt"
printf '%s\n' "$line" # Copy input to standard output
done
}
- 该代码 Shellcheck-干净。
- 有关我在
while ...
行所做更改的解释,请参阅函数 BashFAQ/001 (How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?)。 - 请参阅对 Why is printf better than echo? 的已接受且优秀的回答,以了解为什么我将
echo
替换为printf
。 - 请注意,即使我做了一些更改,如果来自 FD5 的数据是二进制的,
__processing__
函数也不会可靠地工作。 ASCII NUL 字符将丢失(Bash 字符串不能包含它们),这取决于以换行符终止的输入块。我不知道你在这种情况下处理的是哪种数据。它可能不是 Bash 代码可以处理的东西。