將程序的輸出重定向到檔案和流?
概述
我們將瞭解一些將程序輸出重定向到檔案和標準流(如 STDOut 和 STDERR)的同時的方法。
tee 命令
Tee 是我們最常用的 Linux 命令列工具之一,可用於重定向程序的輸出。它也稱為“teeing”或“piping”。tee 命令接受兩個引數 - 您希望將重定向的輸出儲存到的檔名,以及將用於寫入原始輸入的另一個檔名。
重定向stdout
開始了!我們將看一個簡單的例子,將 ls(列表)命令的輸出重定向到 stdout 和一個名為 out.log 的臨時檔案。
$ ls -C | tee /tmp/out.log bin dev home mnt proc run srv tmp var boot etc lib64 opt root sbin sys usr
我們可以確認檔案的內容與執行命令生成的輸出匹配。
$ cat /tmp/out.log bin dev home mnt proc run srv tmp var boot etc lib64 opt root sbin sys usr
另一個需要記住的重要一點是,tee 命令的預設行為是替換檔案的內容。但是,如果需要,我們可以使用 -a(追加)命令在檔案的現有內容之後新增新內容。
將stdout 和stderr 重定向到同一個檔案
在內部,tee 命令充當傳入流的 T 形分流器,以便可以將資料同時定向到輸出流和一個或多個檔案。我們可以利用此知識將程序的 stderrs 重定向到 stdouts 和檔案。
$ (ls -C; cmd_with_err) 2>&1 | tee /tmp/out.log bin dev home mnt proc run srv tmp var boot etc lib64 opt root sbin sys usr bash: cmd_with_err: command not found
我們可以看到 cmd_with_error 是一個未知命令,這意味著它會產生錯誤訊息。我們將 stderror fd(fd=2)重定向到 stdin fd(fd=1),以便 tee 可以同時從兩個檔案讀取。
或者,我們也可以使用 |& 作為 2>&1| 的簡寫來獲得相同的結果 -
$ (ls -C; cmd_with_err) |& tee /tmp/out.log bin dev home mnt proc run srv tmp var boot etc lib64 opt root sbin sys usr bash: cmd_with_err: command not found
現在,讓我們驗證 /tmp/out.log 檔案的內容 -
$ cat /tmp/out.log bin dev home mnt proc run srv tmp var boot etc lib64 opt root sbin sys usr bash: cmd_with_err: command not found
將stdout 和stderr 重定向到不同的檔案
有時我們可能希望將程序的輸出重定向到兩個不同的檔案。我們可以使用程序替換來呼叫 tee 命令。在詳細介紹 tee() 函式之前,以下是一個啟用 tee() 函式監聽特定 fd(檔案描述符)並寫回原始 fd 流和檔案的模板程式碼片段示例。
fd> >(tee file_name fd>&fd)
我們必須指出,fd 只是一個檔案描述符的示例;實際值對於 stdout 為 1,對於 stderror 為 2,對於 stdin 為 0。
現在,讓我們利用我們對流的理解,將命令的 stdout 流重定向到 /tmp/out,將 stderr 流重定向到 /tmp/err。
$ ((ls -C; cmd_with_err) 1> >(tee /tmp/out.log)) 2> >(tee /tmp/err.log 2>&2) bin dev home mnt proc run srv tmp var boot etc lib64 opt root sbin sys usr bash: cmd_with_err: command not found
我們可以確認 /tmp/outfile.log 具有正確的輸出,但 /tmp/errorfile.log 具有錯誤的錯誤訊息。
$ cat /tmp/out.log bin dev home mnt proc run srv tmp var boot etc lib64 opt root sbin sys usr $ cat /tmp/err.log bash: cmd_with_err: command not found
重定向延遲
呼叫 tee (tee) 命令將程序的輸出定向到檔案和 STDOUT 可能會導致延遲。我們將研究一個我們可能希望避免的特定情況,並學習在發生這種情況時如何減輕它。
場景
開始了!我們將編寫一個 Python 程式,每秒列印一次當前時間。
$ cat time.py #!/usr/bin/python from datetime import datetime import time import sys from sys import stdout while True: sys.stdout.write(datetime.today().strftime("%H:%M:%S %p
")) time.sleep(1)
如果我們執行此指令碼,我們將看到指令碼打印出的每個時間戳之間有 1 秒的延遲。
$ ./time.py 9:29:48 PM 9:29:49 PM 9:29:50 PM 9:29:51 PM 9:29:52 PM 9:29:53 PM
延遲重定向
現在,讓我們使用“te”命令將此指令碼的輸出重定向到 stdout 和“time.out”日誌。
$ ./time.py | tee time.out
我們將看到,stdout 在很長一段時間內沒有任何輸出列印,然後會一次性打印出一大塊 stdout。
Python 的內部緩衝區大小設定為 1MB,這意味著當寫入 stdout 時,輸出可能會延遲長達 1 秒才能實際出現在螢幕上。緩衝策略會導致寫入 stdout 的內容透過 4096 位元組(或更大)的緩衝區傳遞,從而減少輸出文字到終端所需的 I/O 次數。
對於互動式應用程式,必須避免從一個頁面重定向到另一個頁面的任何延遲。為了解決重定向延遲問題,我們需要尋找減輕它的方法。
緩解措施
解決此問題的一種方法是確保定期將程式的輸出重新整理到控制檯。
$ cat time.py #!/usr/bin/python from datetime import datetime import time import sys from sys import stdout while True: sys.stdout.write(datetime.today().strftime("%H:%M:%S %p
")) sys.stdout.flush() time.sleep(1) Let's check if the delay has been removed: $ ./time.py | tee time.out 21:46:12 PM 21:46:13 PM
我們可以直接控制應用程式程式碼,因此我們可以更改它。
但是,在許多情況下,程式可能是編譯後的二進位制檔案,我們可能無法訪問其程式碼進行修改。如果我們想避免與寫入 stdout 相關的延遲,我們可以使用 Linux 中的“unbuffer”程式來解決此問題。
讓我們從我們的程式碼中刪除 sys.stdout.flush() 方法呼叫,並使用 unbuffer 命令再次執行重定向。
$ unbuffer ./time.py | tee time.out 21:52:22 PM 21:52:23 PM
更改程式碼後,stdout 寫入操作沒有出現意外延遲。
結論
我們查看了將程式的輸出同時重定向到 stdin 和 stdouts 的幾個示例。我們還學習了一些解決緩衝請求導致的重定向延遲問題的技巧。
資料結構
網路
關係型資料庫管理系統
作業系統
Java
iOS
HTML
CSS
Android
Python
C 程式設計
C++
C#
MongoDB
MySQL
Javascript
PHP