Bash
在 tee 輸出中註入字元串
我正在使用管道在 Centos 6 上通過 bash 實現一些功能。在這些管道中,我想將數據導出到日誌文件中,但是這些數據來自管道中的不同管道,我想通過注入標籤來區分它們在每個日誌行之前。更準確地說,我想做以下事情:
COMMAND1 | (create a line in the log file like: "command1: " + output of the command) | COMMAND2 ...
經過大量研究,我得出以下結論:
COMMAND1 | tee >(ifne echo -n "command1: " >> out.log) | tee -a out.log | COMMAND2
這有效,但有一個問題。第二個
tee
先寫入文件,然後再寫入第一個tee
. 所以我得到:(output of command 1) command1:
代替
command1: (output of command 1)
我懷疑
ifne
延遲足以讓第二個tee
在第一個之前執行。如果我刪除ifne
,它工作正常。問題是我需要ifne
,因為我經常有空輸出,我不想記錄。如何讓第二個發球檯等待第一個發球檯完成?
如果我理解正確,您想用一個標記記錄 COMMAND1 的輸出,表明它來自 COMMAND1。這是一種方法:
COMMAND1 | tee >(sed 's/^/command1: /' >>out.log) | COMMAND2
注意:
- 這會將
command1:
標記放在每行的開頭,而不僅僅是在第一行的開頭,我認為這是可取的,但不是您似乎想要做的。command1
不得包含任何 sed 特殊字元(否則它們需要用反斜杠保護)。- 由於
out.log
是為追加而打開的,因此即使多個命令並行輸出到同一個日誌文件,也不存在輸出重疊的風險。- 由於
out.log
在此程式碼段中僅打開一次,因此所有行都將按順序排列。- 現在是壞消息:如果您並行登錄到同一個文件多次,則無法保證這些行會以所需的順序出現。例如,
echo hello | tee >(sed 's/^/command1: /' >>out.log) | tr a-z A-Z | tee >(sed 's/^/command2: /' >>out.log)
command2: HELLO
之前可能會登錄command1: HELLO
。
- 如果你多次並行登錄到同一個文件,並且一行的內容太長,那麼來自不同實例的行可能會穿插。我認為常見的 sed 實現將通過長度小於
PIPE_BUF
字節的行,但我不確定。鑑於順序和原子性限制,我建議將日誌記錄到單獨的文件中,在這種情況下您不需要前綴。