陷阱

陷阱

我有一个 RFID 读取器,每次成功读取时,它都会将 RFID 标签的唯一 ID 发送到我的 Linux(树莓派)盒子的串行端口。问题是它发送时没有任何换行符。下面是输出的示例:

root@scalepi:~/scale# ./grabserial -d "/dev/ttyUSB4" -b 9600 
$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#$A0112OKD9990001200005643E#

我想用新行将每个条目写入文本文件,如下所示:

$A0112OKD9990001200005643E#
$A0112OKD9990001200005643E#
$A0112OKD9990001200005643E#

正如您所看到的,每个条目都以 $ 开头并以 # 结尾

我尝试使用此行将输出通过管道传输到 sed,在 # 之后添加新行,但输出为零,因为我认为 sed 在处理数据之前正在寻找新行:

./grabserial -d "/dev/ttyUSB4" -b 9600 | sed 's/#/#\r\n/g'

如果我将输出重定向到一个文件,然后 cat 该文件,通过相同的 sed 命令进行管道传输,我会得到我所期望的结果,但我需要能够以这种格式将数据写入文件,以便我可以读取它实时。

root@scalepi:~/scale# ./grabserial -d "/dev/ttyUSB4" -b 9600 > /tmp/test2.txt
^C
root@scalepi:~/scale# cat /tmp/test2.txt | sed 's/#/#\r\n/g'
$A0112OKD9990001200005643E#
$A0112OKD9990001200005643E#
$A0112OKD9990001200005643E#
root@scalepi:~/scale# 

如果有人对我有任何建议,我将不胜感激。谢谢!

编辑-更新

尝试下面的“tr”解决方案后,我能够获得实时输出,但如果我尝试通过管道重定向,或通过 stdout/stderr 重定向,我一次会得到 50-60 行的缓冲结果,而不是得到逐行结果。

以下命令将在串行端口输入时为我提供实时输出:

./grabserial -d "/dev/ttyUSB4" -b 9600 | tr '#' '\n'

以下命令将一次给出 50 或 60 行块的输出(不是实时的):

./grabserial -d "/dev/ttyUSB4" -b 9600 | tr '#' '\n' | sed -u 's/$/#\r/g'

以下命令将一次将 50 或 60 行块输出到文本文件(不是实时):

./grabserial -d "/dev/ttyUSB4" -b 9600 | tr '#' '\n'  > /tmp/test1.txt

FWIW,我使用 cat 读取串行端口而不是“grabserial”得到相同的结果。

以下命令给我实时结果:

cat /dev/ttyUSB4 | tr '#' '\n' 

但是,当我尝试通过管道或标准输出重定向来重定向输出时,我在文本文件中得到缓冲的数据块:

cat /dev/ttyUSB4 | tr '#' '\n' > /tmp/test4.txt

答案1

您可以将#字符翻译(或音译)为换行符

 tr '#' '\n'

所以

./grabserial -d "/dev/ttyUSB4" -b 9600 | tr '#' '\n'

应该给你

$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E
$A0112OKD9990001200005643E

实时。如果你需要英镑符号和/或回车符,您可以将以上内容通过管道传输到

        … sed 's/$/#\r/'

(使用sed(以及一般的正则表达式)用于$表示行尾的事实。

陷阱

tr当输出进入管道或文件时,您可能会遇到缓冲其输出的问题。也许处理这个问题的最好方法是遵循阿尔法的建议 关闭缓冲stdbuf;例如,

./grabserial -d "/dev/ttyUSB4" -b 9600 | stdbuf -oL tr '#' '\n' | sed 's/$/#\r/' > RFIDs.txt

如果不清楚,选项stdbuf是小写o(oh) 和大写L(ell),这表示标准输出应该是行缓冲的。

底线(TL;DR)#1:

所以你应该能够使用

./grabserial -d "/dev/ttyUSB4" -b 9600 | stdbuf -oL tr '#' '\n' > RFIDs.txt

获取#末尾没有 的条目,或者

./grabserial -d "/dev/ttyUSB4" -b 9600 | stdbuf -oL tr '#' '\n' | sed 's/$/#/' > RFIDs.txt

获取#末尾带有 ,但不带有\r, 或 的条目

./grabserial -d "/dev/ttyUSB4" -b 9600 | stdbuf -oL tr '#' '\n' | sed 's/$/#\r/' > RFIDs.txt

获取条目# \r在最后。

底线(TL;DR)#2:

你还没有说你如何终止命令。如果您输入Ctrl+ C,则可能造成问题1 .如果是这样,请尝试:

  • 使用 , 将上述命令行之一放入后台&,然后
  • 当你准备退出时,执行 aps并获取进程的 PID grabserial,然后
  • 用命令杀死它kill

底线(TL;DR)#3:

您说您需要能够实时读取数据,但无需详细说明。如果您有一些能够从标准输入读取的程序/脚本,请尝试

./grabserial -d“/dev/ttyUSB4”-b 9600 | stdbuf -oL tr '#' '\n' | stdbuf -oL tr '#' '\n' | stdbuf -oL tr '#' '\n' | sed 's/$/#\r/'| T 恤 RFIDs.txt | 你的程序 

这应该将数据写入输出文件,同时将其传输到您的程序。

底线(TL;DR)#4:

事实上,如果cat和 一样有效grabserial,那么您实际上不需要其中任何一个;像

stdbuf -oL tr '#' '\n' < /dev/ttyUSB4 | sed 's/$/#\r/' > RFIDs.txt

应该也能正常工作。
____________
1根据您的更新,这可能不是您的问题,但我将其留在这里,以防对其他人有帮助。


请注意,tr基本上是在一对一的基础上运行的。 (有一些选项可以做一些稍微花哨的事情。)所以,例如,

tr 'abc…' 'ABC…'

将替换aA、  bwith B、  cwithC等。所以你不能做类似的事情

tr '#' '#\r\n'

答案2

因为sed通常会缓冲其输出,直到缓冲区大小填满(可能是 4K 字节),所以您可以使用-uGNU 特定选项来取消缓冲输出。

请参见关闭管道中的缓冲以及相关的回答sed

相关内容