使用 tee 從 GitHub 複製管道輸出未命中輸出
我想我會將複製 GitHub 儲存庫的輸出記錄到文件中。如果我跑
git clone git@github.com:my_repo/my_repo.git | tee -a log
我得到一個空
log
文件,但命令行輸出如下:Cloning into 'my_repo'... remote: Enumerating objects: 284, done. remote: Counting objects: 100% (228/228), done. remote: Compressing objects: 100% (133/133), done. remote: Total 284 (delta 122), reused 162 (delta 69), pack-reused 56 Receiving objects: 100% (284/284), 873.22 KiB | 2.71 MiB/s, done. Resolving deltas: 100% (138/138), done.
這對我來說已經有點神秘了。我想我應該嘗試通過管道傳輸
stderr
和stdout
傳輸到文件git clone git@github.com:my_repo/my_repo.git 2>&1 | tee -a log
現在
log
文件和命令行都得到了複製到“my_repo”…
我在這裡想念什麼?如何將這些
remote: ...
行放入文件中tee
?
如評論中所述,
git
檢查標準輸出/錯誤是否是終端。如果是,程序會在終端輸出中添加一些額外的糖,以文本形式指示進度和一些統計資訊。如果不是,它會將標準流的輸出保持在最低限度。在內部,它使用
isatty()
例如此處所示的範例。這是命令行程序的一種常見做法。最重要的是要剝離 ANSI 著色,因為您通常不希望將其放入文件中,弄亂管道處理等。例如檢查:/bin/ls --color=auto -1 # ls print column in pipe /bin/ls --color=auto | sed -n 'l' /bin/ls --color=always | sed -n 'l'
可以選擇通過
git
說-q
或--quiet
始終抑製或--progress
始終列印來覆蓋這一點。進度輸出被列印到stderr
而不是(通常)用於消費。儘管如此:git clone --progress foo/bar.git 2>&1 | tee log
其他程序可能沒有類似的選項,並且必須跳過一些障礙才能獲取數據。這樣做是為了盡量減少混亂等,例如在一個仍然列印到的自動腳本中
stderr
,但將其減少為錯誤消息。例如git
:$ git clone -q https://nonexistig-url.com/foo.git fatal: https://nonexistig-url.com/foo.git/info/refs not valid: is this a git repository? $ echo $? 128
沒有進展,但人們會收到錯誤消息,這通常在事後場景中更有趣。複製過程本身的進展是沉默的。
有時可以通過後處理或執行其他或附加命令通過其他方式獲取資訊。例如
git count-objects -v
.假終端
如果一個人真的想要被抑制的輸出,並且程序沒有類似的選項,那麼
git
一種選擇是讓程序“認為”它寫入終端,即使它沒有。實現這一目標的各種方法;我用於臨時事物的一種方法是我只是出於某種原因想要它,即用始終返回 true的系統替換系統isatty()
。echo 'int isatty(int fd) { return 1; }' | \ gcc -O2 -fpic -shared -ldl -o faketty.so -xc - strip faketty.so chmod 400 faketty.so
與包裝腳本一起使用
faketty
:#! /bin/sh - LD_PRELOAD=/path/to/faketty.so "$@"
並用作:
faketty git clone foo
正如程式碼所示,它確實不做任何文件描述符檢查等,而只是一個 hack。
出生數據的問題
該
git clone
命令不會為輸出著色,但會顯示進度。這樣做的方法是重複覆蓋終端中的同一行。它通常寫道:Cloning into 'foo'...\n remote: Enumerating objects: 236, done. \n \rReceiving objects: 0% (1/236) \rReceiving objects: 1% (3/236) \rReceiving objects: 2% (5/236) ... \rReceiving objects: 79% (187/236) \rremote: Total 236 (delta 0), reused 0 (delta 0), pack-reused 236 \n ... \rReceiving objects: 99% (234/236) \rReceiving objects: 100% (236/236) \rReceiving objects: 100% (236/236), 79.45 MiB | 104.73 MiB/s, done.\n ...
在這裡
\r
,就像在輸入中一樣,告訴終端將游標移動到行首,而不是\n
像在換行/行尾中那樣,將游標移動到下一行的開頭。結果,每次寫入都會覆蓋前一行,直到該
remote: Total 236 …
行結束,\n
並且該過程在下一行繼續,從而為查看者帶來類似這樣的結果:Cloning into 'foo'... remote: Total 236 (delta 0), reused 0 (delta 0), pack-reused 236 Receiving objects: 100% (236/236), 79.45 MiB | 104.73 MiB/s, done. ...
包括每次寫入的視覺進度。對於這種情況
cat
,當終端解釋輸入時,一個簡單的日誌看起來還可以,但 ased -n l log
將顯示真實內容。(可選sed 's/\r/\n/g' log
)顯示*“線條”*之類的東西。清理
對於這種情況,一個簡單的管道或日誌槽的後處理
sed
就足夠了:sed 's/.*\r//' # Optionally to trim trailing white space, either of: sed 's/.*\r//;s/ \+$//' sed 's/.*\r\| \+$//g'
它有點脆弱,因為進度輸出可能會在版本、版本等之間發生變化,因此不能保證資訊會相同。如果輸出有顏色,則需要進一步刪除這些序列。
一個人將失去顯示的進度(實時計數),並且只有在命令之前通過管道傳輸時才能獲得最終
git
結果。sed``tee