語境
我正在嘗試開發一個腳本來統一我當前作業的腳本來決議一些視頻檔案。第一個非常簡單,只需確保所有視頻檔案都在 mkv 容器上。接下來的幾個呼叫mkvmerge -i會檢查檔案中的字幕、標簽、附件和其他不需要的額外內容(有時使用find, 有時使用findstrRegEx 來完成)。
這是輸出的mkvmerge -i樣子:
File 'test.mkv': container: Matroska
Track ID 0: video (AVC/H.264/MPEG-4p10)
Track ID 1: audio (Opus)
Track ID 2: subtitles (SubRip/SRT)
Attachment ID 1: type 'image/jpeg', size 30184 bytes, file name 'test.jpg'
Attachment ID 2: type 'image/jpeg', size 30184 bytes, file name 'test2.jpg'
Attachment ID 3: type 'image/jpeg', size 30184 bytes, file name 'test3.jpg'
Chapters: 9 entries
目前,我只是將它通過管道傳輸到findorfindstr并搜索諸如“字幕”、“位元組”或: [0-9].
我的目標是,對于每個處理過的檔案,每個檔案mkvmerge -i只呼叫一次,而不是每個腳本呼叫一次。這是我重新開始的一個舊專案,我之前的嘗試可以在這個問題中看到。
問題
按照這個答案,我設法將 的輸出附加mkvmerge -i到一個變數 ( %mkvmergeinfo%) 中,現在我所要做的就是通過管道傳遞這個變數幾次,然后讓其余的代碼相應地采取行動。這是它目前的樣子:
for /f "usebackq delims= eol=$" %%c in (`echo !mkvmergeinfo! ^| find /c /i "subtitles"`) do (
if [%%c]==[0] (
...
如果我更改echo !mkvmergeinfo!為mkvmerge -i,其余代碼可以正常作業,但是現在我正在嘗試傳遞一個多行命令,當我添加echo %%cafter 時do,它只顯示第一行echo !mkvmergeinfo!(我已經檢查過并且它確實包含所有行)。
我試圖解決這個問題,將括號內的整個命令替換為對標簽的呼叫,這將執行回聲和管道,但這不起作用。
是否有另一種解決問題的方法,而不僅僅是將輸出寫入檔案并決議該檔案?
uj5u.com熱心網友回復:
阿for /F與一組命令來處理在后臺一個開始多個Windows命令處理器的命令列結果的輸出%SystemRoot%\System32\cmd.exe /c和所附作為附加自變數的命令列。因此,對于在后臺運行的此命令列程,不啟用延遲變數擴展,因為echo !mkvmergeinfo!. 有必要cmd.exe使用選項/V:ON 左選項/c和要執行的命令列來運行后臺。但這是不可能的,除了運行兩個額外的cmd.exe,第一個帶有/c和一個%ComSpec% /D /V:ON /C ...以第二個開頭的命令列,cmd.exe如aschipfl在上面的評論中所建議的那樣。
我建議mkvmerge.exe -i為每個*.mkv檔案運行一次,并僅使用FOR和IFcmd.exe等內部命令處理輸出,而根本不使用and 。find.exefindstr.exe
例子:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for %%G in (*.mkv) do (
echo/
echo Processing file "%%G" ...
for /F "delims=" %%H in ('mkvmerge.exe -i "%%G"') do (
echo/
echo Processing info line: %%H
for /F "tokens=1,3,4* delims=:( " %%I in ("%%H") do (
if "%%I" == "Track" (
for /F "delims=)" %%M in ("%%L") do (
if "%%K" == "video" (
echo ... Track %%J is a video track with video codec %%M
) else if "%%K" == "audio" (
echo ... Track %%J is an audio track with audio codec %%M
) else if "%%K" == "subtitles" (
echo ... Track %%J is a subtitles track with subtitles codec %%M
)
)
) else if "%%I" == "Attachment" (
echo ... Attachment %%J is %%K %%L
)
)
)
)
endlocal
如何mkvmerge.exe -i "%%G"進一步處理每行輸出取決于您。這只是一個演示,它導致 file 的發布資訊的以下輸出test.mkv。
Processing file "test.mkv" ...
Processing info line: File 'test.mkv': container: Matroska
Processing info line: Track ID 0: video (AVC/H.264/MPEG-4p10)
... Track 0 is a video track with video codec AVC/H.264/MPEG-4p10
Processing info line: Track ID 1: audio (Opus)
... Track 1 is an audio track with audio codec Opus
Processing info line: Track ID 2: subtitles (SubRip/SRT)
... Track 2 is a subtitles track with subtitles codec SubRip/SRT
Processing info line: Attachment ID 1: type 'image/jpeg', size 30184 bytes, file name 'test.jpg'
... Attachment 1 is type 'image/jpeg', size 30184 bytes, file name 'test.jpg'
Processing info line: Attachment ID 2: type 'image/jpeg', size 30184 bytes, file name 'test2.jpg'
... Attachment 2 is type 'image/jpeg', size 30184 bytes, file name 'test2.jpg'
Processing info line: Attachment ID 3: type 'image/jpeg', size 30184 bytes, file name 'test3.jpg'
... Attachment 3 is type 'image/jpeg', size 30184 bytes, file name 'test3.jpg'
Processing info line: Chapters: 9 entries
所以第一行和最后一行資訊輸出并沒有真正處理,而對第一個子字串(令牌)區分大小寫的行進行進一步處理Track或Attachment。
第二個FOR命令列導致在后臺啟動,Windows 安裝到C:\Windows另一個 Windows 命令處理器中,當前檔案的以下命令列為test.mkv:
C:\Windows\System32\cmd.exe /c mkvmerge.exe -i "test.mkv"
Windows 命令處理器必須首先mkvmerge.exe使用環境變數PATHEXT和PATH. 因此,如果批處理檔案必須處理 100 個.mkv檔案,則必須執行很可能總共有數千次檔案系統訪問才能一次又一次地找到該可執行檔案。使用完全限定檔案名(即mkvmerge.exe完整路徑)將有助于將檔案系統訪問次數減少到.mkv100 次執行 100 次mkvmerge.exe.
Once mkvmerge.exe is found, the second cmd.exe started in background calls this executable with its full path and passes the two arguments to it. mkvmerge.exe outputs the data to handle STDOUT of the background command process.
The output to handle STDOUT of the background command process is captured by cmd.exe processing the batch file and FOR processes the lines one after the other after started cmd.exe closed itself after mkvmerge.exe finished.
FOR with option /F ignores always empty lines. That is no problem here.
Non-empty lines would be split up by default into substrings (tokens) using normal space and horizontal tab as string delimiters, then the first substring would be checked on beginning with a semicolon which is the default end of line character in which case the line would be ignored also for further processing and finally the first space/tab delimited substring is assigned to the specified loop variable H. But that default line processing behavior is not wanted in this case. For that reason delims= is used to defined an empty list of delimiters which results in getting the entire captured line assigned to the loop variable H, except the line would start with ; which can be excluded here because of mkvmerge.exe does not output a line with a semicolon at the beginning.
The entire line is output by the demonstration code to the console window so that it can be seen how the line looks like which is processed further.
The second for /F loop makes now the real job of processing the data of the line. The line assigned to loop variable H is specified in double quotes inside the round brackets resulting in FOR interpreting the line as string to process like a line captured from a command process executed in background or a line read from a text file.
This time the string delimiters are defined with a colon, an opening round bracket and a normal space using delims=:( . There is additionally specified with tokens=1,3,4* that of interest is not only the first substring, but the first, the third, the fourth and the rest of the line not further split up into substrings using the delimiters.
For example, let us look on what happens now with the following line:
Track ID 0: video (AVC/H.264/MPEG-4p10)
This line is split up to:
Trackbeing assigned to the specified loop variableI.IDwhich is not further processed at all.0which is assigned to next but one loop variableJaccording to the ASCII table.
This is the reason for loop variables being case-sensitive.videowhich is assigned to loop variableKaccording to the ASCII table.AVC/H.264/MPEG-4p10)which is the rest of the line being assigned to the loop variableL.
The strings assigned to the loop variables I to L are processed further with the IF conditions whereby the round bracket at end of the codec string of a line beginning with Track is removed using one more for /F command with delims=).
It would be also possible to directly split up the captured lines into substrings as demonstrated with the following code which additionally ignores all lines beginning with Attachment on having before processed lines beginning with Track.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for %%G in (*.mkv) do (
set "Tracks="
echo/
echo Processing file "%%G" ...
for /F "tokens=1,3,4* delims=:( " %%H in ('mkvmerge.exe -i "%%G"') do (
if "%%H" == "Track" (
set "Tracks=1"
for /F "delims=)" %%L in ("%%K") do (
if "%%J" == "video" (
echo ... Track %%I is a video track with video codec %%L
) else if "%%J" == "audio" (
echo ... Track %%I is an audio track with audio codec %%L
) else if "%%J" == "subtitles" (
echo ... Track %%I is a subtitles track with subtitles codec %%L
)
)
) else if not defined Tracks (
if "%%H" == "Attachment" echo ... Attachment %%I is %%J %%K
)
)
)
endlocal
The output of this demonstration code for file test.mkv is:
Processing file "test.mkv" ...
... Track 0 is a video track with video codec AVC/H.264/MPEG-4p10
... Track 1 is an audio track with audio codec Opus
... Track 2 is a subtitles track with subtitles codec SubRip/SRT
There is undefined first with set "Tracks=" the environment variable Tracks for each file before processing the lines output by mkvmerge.exe. If there is a line beginning with Track, the environment variable Tracks is defined with value 1 whereby the value does not matter.
On all other lines there is checked first if the environment variable Tracks is still not defined. If this condition is not true because of at least one line beginning with Track was processed before, the line is completely ignored. Otherwise there were no track information processed before and for that reason lines beginning with Attachment are processed next with printing information about the attachment. The first line with File and the last line with Chapters are still completely ignored in any case.
要了解使用的命令及其作業原理,請打開命令提示符視窗,在其中執行以下命令,并仔細閱讀每個命令顯示的所有幫助頁面。
echo /?endlocal /?for /?if /?setlocal /?
另請參閱我對Windows 批處理檔案中與 NEQ、LSS、GTR 等等效的符號的回答,以了解為什么將兩個字串括起來進行比較是"有意義的,而將它們括在中[并]由于方括號而沒有意義對于 Windows 命令處理器沒有特殊意義。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/406297.html
標籤:
上一篇:根據情節選擇復制檔案
