3

我有一个非常小的批处理脚本,它正在提取大量文件。该脚本旨在与压缩数据一起交付给其他用户。

现在我的问题是这个压缩工具正在将大量数据输出到 cmd 窗口中。我认为这会让很多用户感到困惑,因为输出真的是“正在运行”。它基本上显示了每行的百分比以及它如何以何种速度(CPU 和 HDD)解压缩。很多令人困惑的数据,没有人需要看到。现在我真的不喜欢抑制程序的所有输出,在我看来,向用户提供关于减压已经达到多远的反馈很重要。那么是否可以重定向输出并仅读取该输出的前三位并在一行中将其传递给用户?所以用户只看到一个前进的百分比(一行),而不是每秒有 20 条新行的所有这些数据?

这里是它目前的外观示例:http: //i.imgur.com/5w5LH.png 压缩工具是 SREP,我的操作系统 Win 7 x64。

4

2 回答 2

5

如果你使用windows批处理,它可以完成,但这并不简单,因为你通常会用FOR/F-Loop来做这件事。

for /f "delims=" %%a in (7z packit ...) do ...
问题就在这里,for-loop 将首先收集所有数据并等待结束,7z然后再处理任何输出行。

唯一的方法是重定向输出,并同时扫描它。
但要做到这一点,您需要第二个线程(最好在同一个 cmd 窗口中)。

像这样的东西可以完成这项工作

@echo off
echo start
setlocal EnableDelayedExpansion
if "%1"=="internal" goto :readThread
start /b cmd /c ""%~f0" internal"

rem *** myPacker pack here and redirect the output
del archive.7z
del output.tmp
start "title" /b /wait cmd /c  "%ProgramFiles%\7-Zip\7z" u  archive \tempx\*.rtf \tempx\*.pdf ^> output.tmp
echo EOF>>output.tmp
echo ENDE
:waitForEnd
(
> lock (
  rem
) || goto :waitForEnd
) 2> nul
exit /b

:readThread

for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
echo ####!cr!x
echo(
<output.tmp ( 
    echo ## before
    call :readData 2> lock
    echo after
)
exit /b

:readData
set "var="
set /p var=
if "!var!"=="EOF" exit /b
if defined var (
  <nul set /p ".=Processing files, currently at !var:~0,4!!CR!"
)
goto :readData
于 2012-05-08T19:35:21.327 回答
4

这是一个简单的混合批处理/JScript 脚本,我认为它可以满足您的需求。

show3.bat

@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScrpt comment

::: Batch part ::::
@cscript //nologo //e:JScript "%~f0"
@exit /b

*** JScript part ***/
while( !WScript.StdIn.AtEndOfStream ) {
  WScript.StdOut.Write( '\x08\x08\x08' + WScript.StdIn.ReadLine().substr(0,3) );
}
WScript.StdOut.WriteLine();

用法:

yourCommand | show3

该脚本可以简化为纯 JScript,但使用起来就不那么方便了:

show3.js

while( !WScript.StdIn.AtEndOfStream ) {
  WScript.StdOut.Write( '\x08\x08\x08' + WScript.StdIn.ReadLine().substr(0,3) );
}
WScript.StdOut.WriteLine();

用法:

yourCommand | cscript //nologo show3.js

编辑正如 jeb 评论的那样,您不需要任何 redist 即可使用此解决方案。

我采用了 jeb 的回答中的一些概念,并将整个过程组合成一个混合脚本。不需要独立的“show3”文件。

@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScrpt comment

:: ***** Batch part ******
@echo off

REM whatever batch code you need goes here

yourCommand | cscript //nologo //e:JScript "%~f0"

REM whatever batch code you need goes here

exit /b

****** JScript part ******/
while( !WScript.StdIn.AtEndOfStream ) {
  WScript.StdOut.Write( '\x08\x08\x08' + WScript.StdIn.ReadLine().substr(0,3) );
}
WScript.StdOut.WriteLine();

yourCommand将是您使用的任何压缩命令。yourCommand 2>&1根据您的评论,如果您想要的输出打印到标准错误而不是标准输出,听起来您可能必须使用。

我创建了一个“yourCommand.bat”文件用于测试目的。它粗略地模拟了您为压缩程序描述的输出行为。

@echo off
for /l %%A in (1 1 100) do (
  echo %%A   "I don't want to see this quoted text"
  for /l %%B in (1 1 50000) do rem
)

最后,如果你真的想要一个纯批处理的解决方案,我大大简化了jeb的解决方案。我删除了临时文件并使用了管道。

@echo off
if "%~1"==":show3" goto :show3
REM whatever batch code you need goes here

(yourCommand & echo EOF) | "%~f0" :show3

REM whatever batch code you need goes here
exit /b

:show3
setlocal enableDelayedExpansion
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
:read
set "ln="
set /p "ln="
if not defined ln goto :read
for /f "tokens=1* delims= " %%A in ("!ln!") do if "%%A%%B" equ "EOF" (
  echo(
  exit /b
)
<nul set /p "=!ln:~0,3!   !cr!"
goto :read

编辑-我修改了 EOF 测试以忽略任何前导或尾随空格。这应该使代码更加健壮。

于 2012-05-08T19:11:34.187 回答