2013-05-01 70 views
5

對於上下文,我試圖創建一個簡化ffmpeg的實時控制檯輸出的shell腳本,只顯示當前正在編碼的幀。我的最終目標是將這些信息用於批處理的某種進度指示器。實時刪除外殼中的回車

對於那些不熟悉ffmpeg輸出的人來說,它會將編碼的視頻信息輸出到stdout並將控制檯信息輸出到stderr。另外,當它實際上顯示編碼信息時,它使用回車來保持控制檯屏幕不被填滿。這使得簡單地使用grep和awk來捕獲適當的行和幀信息是不可能的。

的第一件事情我已經試過被替換使用TR回車:

$ ffmpeg -i "ScreeningSchedule-1.mov" -y "test.mp4" 2>&1 | tr '\r' '\n'

這工作,因爲它顯示的實時輸出到控制檯。但是,如果我將這些信息傳遞給grep或awk或其他任何內容,則tr的輸出將被緩衝,並且不再是實時的。例如:$ ffmpeg -i "ScreeningSchedule-1.mov" -y "test.mp4" 2>&1 | tr '\r' '\n'>log.txt會導致立即填充一些信息的文件,然後5-10秒後,會將更多行拖入日誌文件。

起初我以爲sed對於這個很好:$ # ffmpeg -i "ScreeningSchedule-1.mov" -y "test.mp4" 2>&1 | sed 's/\\r/\\n/',但是它到達了所有回車的行,並且在處理完成之前一直等到處理完成之後才嘗試做任何事情。我認爲這是因爲sed在逐行的基礎上工作,並且在完成其他任何事情之前需要完成整個行,然後它不會取代回車。我已經嘗試了各種不同的正則表達式的回車和新行,並且還沒有找到替代回車的解決方案。我正在運行OSX 10.6.8,所以我使用BSD sed,這可能會導致這種情況。

我也嘗試將信息寫入日誌文件並使用tail -f來讀回它,但我仍然遇到了實時替換回車的問題。

我已經看到,在python和perl中有這個解決方案,但是,我不願立即去那條路線。首先,我不知道python或perl。其次,我有一個完全功能的批處理外殼應用程序,我需要移植或想出如何與python/perl集成。可能不難,但不是我想要進入,除非我絕對必須。所以我正在尋找一個shell解決方案,最好是bash,但是任何OSX shell都可以。

如果我想要的東西根本不可行,那麼我想我會在那裏過橋。

回答

4

如果它只是接收應用程序在輸出管道後輸出緩衝的問題。然後你可以嘗試使用gawk(和一些BSD awk)或mawk這可以刷新緩衝區。例如,嘗試:

... | gawk '1;{fflush()}' RS='\r\n' > log.txt 

另外,如果你awk不支持這一點,你可以通過反覆關閉輸出文件,並追加下一行強制此...

... | awk '{sub(/\r$/,x); print>>f; close(f)}' f=log.out 

或者你可以只使用外殼,例如在bash

... | while IFS= read -r line; do printf "%s\n" "${line%$'\r'}"; done > log.out 
+0

非常感謝!你的第一個命令完美無缺,儘管我在OSX上使用了'awk'。這讓我非常頭疼! – Seth 2013-05-01 14:41:01

+1

有一件事要添加到這個偉大的答案:檢查您的安裝的awk/gawk/mawk文檔以瞭解RS的解釋。在我的本地OSX框中,awk對記錄分隔符有一個隱式OR(或者是回車符或換行符)。在我的Ubuntu服務器上,gawk 4.0.1將RS解釋爲一個正則表達式,如果它有多個字符的話。所以,我必須使用'RS ='\ r | \ n'來實現我在OSX上看到的相同行爲。 – ajmicek 2015-11-16 00:41:38

4

當stdout和stderr連接到終端時,Libc使用行緩衝,並在連接到管道時使用完全緩衝(使用4KB緩衝區)。這發生在產生輸出的過程中,而不是在接收過程—這是ffmpeg的錯,在你的情況下,不是tr的。

unbuffer ffmpeg -i "ScreeningSchedule-1.mov" -y "test.mp4" 2>&1 | tr '\r' '\n' 
stdbuf -e0 -o0 ffmpeg -i "ScreeningSchedule-1.mov" -y "test.mp4" 2>&1 | tr '\r' '\n' 

嘗試使用unbuffer or stdbuf禁用輸出緩衝。

+0

我對此有點困惑。如果我只是將stderr管理到一個文件,即'2> log.txt',我就可以實時更新文件(如果我在文件中使用了'tail -f',我就會看到我認爲是行緩衝更新;比'tr'緩衝更快)。 在'unbuffer'和'stdbuf'方面,我似乎沒有在我的系統上使用它們,儘管我確實有'expect'這讓我覺得我會有'unbuffer'。我希望對腳本有一定的可移植性,所以如果我需要使用非標準的應用程序,我想要一個可以隨我的腳本一起移動的靜態可執行文件。 – Seth 2013-05-01 14:08:36

+0

好吧,我試着'unbuffer'通過自己從指令[這裏](http://superuser.com/questions/59497/writing-tail-f-output-to-another-file)。這仍然只會在緩衝塊中得到更新,而不是按行。 – Seth 2013-05-01 14:32:16

1

進程之間的數據的中的管體的緩衝與一些系統限制,這是至少在我的系統(Fedora的17)不可能控制以修改:

$ ulimit -a | grep pipe 
pipe size   (512 bytes, -p) 8 
$ ulimit -p 1 
bash: ulimit: pipe size: cannot modify limit: Invalid argument 
$ 

雖然這種緩衝主要與如果消費者沒有以相同的速度消費,生產者在停止生產之前可以生產多少多餘的數據,這可能也會影響少量數據交付的時間(不太確定這一點)。

這是管道數據的緩衝,我認爲這裏沒有太多的調整。但是,讀取/寫入管道數據的程序也可能會緩衝標準輸入/標準輸出數據,因此您希望避免出現這種情況。

這裏是一個Perl腳本,應該做的最小輸入緩衝翻譯並沒有輸出緩衝:

#!/usr/bin/perl 
use strict; 
use warnings; 

use Term::ReadKey; 
$ReadKeyTimeout = 10; # seconds 

$| = 1; # OUTPUT_AUTOFLUSH 

while(my $key = ReadKey($ReadKeyTimeout)) { 
     if ($key eq "\r") { 
       print "\n"; 
       next; 
     } 
     print $key; 
} 

然而,正如已經指針了,你應該確保ffmpeg的不一樣,如果緩衝輸出想要實時響應。