
我正在運行嵌入式 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