我正在运行嵌入式 Linux,我的命令行有console=/dev/ttyO0,...
.我有终端程序连接到这个 UART 并且可以看到一切系统产生的。
现在,当在现场运行时,我想将所有这些输出存储在文件中(我已连接媒体)。但是我使用syslogd
、和 Co. 所做的所有努力klogd
都logger
没有给我想要的结果 - 有些消息被存储,但有些则没有 - 通常是最重要的。
例如,如果我运行:
myapplication.sh | logger
echo
我也从应用程序中看到了命令syslog
,也看到了一些驱动程序消息。print
但是,如果应用程序因分段错误而崩溃,则不会记录此信息。但这是最有价值的!
所以,最好也是最想要的就是重定向ttyO0
到文件,但是如何呢?
我找到了这样的推荐:
(stty raw; cat > received.txt) < /dev/ttyO0
但这不起作用:我可以键入命令,例如ifconfig
,但回复既不会出现在文件中,也不会出现在控制台上。即使文件没有创建...:-(
如果可以同时拥有文件和串行控制台,那就太棒了。但文件具有更高的优先级。
非常感谢您的帮助!
更新我找到了解决方案并将其添加到答案部分。
答案1
您似乎忽略了一个相当基本的事实。每个可管道程序都依赖于这样一个事实:三无论程序调用它,标准文件描述符都处于预打开状态。在大多数涉及管道的情况下,调用程序将是命令 shell。
这三个文件描述符是:
- 文件描述符#0:标准输入流,或
stdin
简称。 - 文件描述符#1:标准输出流,或
stdout
简称。 - 文件描述符#2:标准错误输出流,或
stderr
简称。
当程序未通过管道传输或重定向来读/写文件时,所有这三个文件描述符通常都会指向当前登录会话正在其上运行的 TTY 设备。如果故意将程序作为守护程序或后台/非交互式进程启动,则所有这些都可能会定向到文件或/dev/null
,或者可能定向到某种日志记录工具。
错误消息通常被输出到stderr
流中,这样它们就不会与可能的管道数据输出混合在一起。但在像你这样的情况下,当你想要捕捉全部对于输出,您需要明确告诉系统获取两个流。
如果您想将所有输出传递myapplication.sh
到管道中,您可能必须执行以下操作:
myapplication.sh 2>&1 | logger
上面2>&1
说“将文件描述符 #2 重定向到 #1 所在的同一位置”,然后您可以同时通过管道传输它们。
您可以使用如下小脚本自行测试:
#!/bin/sh
echo "this is stdout"
echo "this is stderr" >&2
意思>&2
是“获取该命令的标准输出并将其发送到标准错误流中”。这可能是stderr
在脚本中生成输出的最简单方法。
现在,如果您运行此脚本./test.sh | od -t x1z
以获取十六进制转储形式的输出,您将得到以下结果:
$ ./test.sh | od -t x1z
this is stderr
0000000 74 68 69 73 20 69 73 20 73 74 64 6f 75 74 0a >this is stdout.<
0000017
所以命令只stdout
处理输出od
。
如果您添加2>&1
来合并两个流,您将得到以下结果:
$ ./test.sh 2>&1 | od -t x1z
0000000 74 68 69 73 20 69 73 20 73 74 64 6f 75 74 0a 74 >this is stdout.t<
0000020 68 69 73 20 69 73 20 73 74 64 65 72 72 0a >his is stderr.<
0000036
现在两个输出都被发送到管道中,这就是您在| logger
.
第二个命令行正在捕获嵌入式设备从终端程序接收的任何内容,而不是嵌入式设备发送到终端的内容:
(stty raw; cat > received.txt) < /dev/ttyO0
您说您正在开发一个使用内核参数的嵌入式系统console=/dev/ttyO0
,因此本质上将/dev/console
是一个串行端口,而不是图形显示器(它甚至可能不存在于嵌入式设备中)。
如果您在嵌入式设备上运行该命令,则括号内的命令将以其标准输入流(文件描述符#0,或stdin
简称)分配给/dev/ttyO0
.但是,如果您通过连接到的串行线路输入该命令ttyO0
,则默认情况下可能会如此,因此此输入重定向可能只是重新强制执行原样的情况。
该/dev/ttyO0
设备是连接到另一台计算机上的终端程序的 UART 的直接表示。当你阅读它时,你会得到仅您在终端程序中输入的内容:无法读回之前发送到其中的任何输出。写入其中的任何内容都会直接进入串行电缆末端的终端程序。
串行端口上的 Unix 命令行通常在远程回声原理:为了查看您在终端程序上写入的内容,嵌入式系统上的 TTY 驱动程序必须将您键入的每个字符的副本发送回终端程序。这种行为是不对称的:终端程序不会也发回通过串行端口连接接收到的任何内容的副本。
TTY 驱动程序是一件复杂的事情,因为 Unix 传统要求它能够做很多事情 - 远程回显功能只是其中之一。
当你使用时stty raw
,你就有效地关闭 TTY 驱动程序的所有通常有用的功能,包括远程回显功能。因此,从那时起,除非有东西显式地读取/dev/ttyS0
并立即将其写回其中,否则您将看不到在终端程序上写入的内容。
stty raw
命令退出后,来自终端程序的任何输入都将进入该cat
命令,在不带参数调用时,该命令会将其按原样传递到其标准输出中。但它的标准输出现在已重定向到文件received.txt
.所以发生的事情是只有您在终端程序上键入的内容才会写入文件中直到cat
命令结束 - 并且仅当它获得文件结束字符(通常为Control+D)时才结束。
(由于执行重定向的 shell 可能会进行任何缓冲,因此可能不会向文件中输出任何内容,received.txt
除非您以文件结束字符结束键入,和/或键入多行文本。)
因此,除了关闭 TTY 驱动程序功能之外,(stty raw; cat > received.txt) < /dev/ttyO0
嵌入式系统上的 根本不执行任何操作来捕获任何输出正在写入/dev/ttyO0
.该命令的唯一用途是当您排除故障时串口连接:如果您怀疑您的终端程序以某种方式破坏了您发送出去的字符,那么这是捕获终端程序以其最原始形式发送到嵌入式设备的任何内容的方法。
如果你想录音绝对是一切如果发生在 UART 连接上,包括例如内核恐慌消息,那么最好的方法可能是告诉另一台计算机上的终端程序记录所有流量。许多终端程序都内置了此功能。
这是因为如果内核出现问题,实际上可能无法再将任何内容写入磁盘文件。从 UART 发送错误消息文本并相信接收它的人会捕获它要简单得多。
答案2
好吧,我想我找到了答案。我非常非常惊讶,这样一个简单且必需的恕我直言的事情是以如此“不规则”的方式解决的,但这就是生活......:-)
无论如何,感谢telcoM
谁给了我参考资料,这些参考资料导致了参考资料和更多参考资料,终于找到了ttyrpl
完全符合我想要的包。
软件包维护大约在 7-10 年前就停止了,我花了一些时间才将它采用到我的 Linux 版本和所需的库中,但它确实有效!
它完全符合我的要求 - 收集 ttyS0/ttyO0 的输出并将其存储到文件中。并且有很多奇特的选项,尽管我不需要它们......:-)
答案3
尝试使用 picocom 而不是 console=/dev/ttyS0。还有其他工具,但 picocom 听起来最简单。
如果您使用这些工具之一,则可以在输出上使用管道和三通。
picocom /dev/ttyS0 -b 115200 -l | tee my.log
答案4
尝试https://tio.github.io- 它支持记录到文件。例如:
tio /dev/ttyS0 --log --log-file my-log.txt
或者
tio /dev/ttyS0 --log
它将串行输出记录到具有自动生成的文件名的文件中,例如tio_ttyS0_2022-09-14T08:56:09.log