I have a very small batch script which is extracting a quite amount of files. The script is meant to be delivered with the compressed data to other users.
Now my problem is that this compression tool is outputting a ton of data into the cmd window. I think this will confuse a lot of useser because the output is really "running". It basically shows a percentage with each line and how it decompressed at which speed (CPU and HDD). A lot of confusing data that no one needs to see. Now I don't really like suppressing all the output of the program, giving the user feedback on how far the decompression already got would be important in my opinion. So is it possible to redirect the output and read just the first three digits of that output and deliver that to the users in a single line? So the users only sees an advancing percantage (in one line) and not 20 new lines every second with all this data?
Here an example of how it looks at the moment: https://i.sstatic.net/guTYP.png The compression tool is SREP, my OS Win 7 x64.
If you use windows batch, it can be done, but it's not simple, as you would normally do this with a FOR/F-Loop.
Like for /f "delims=" %%a in (7z packit ...) do ...
The problem is here, that the for-loop will first collect all data and wait for the end of 7z before it process any line of the output.
The only way is to redirect the output, and to scan it simultaneously.
But to do that you need a second thread (at best in the same cmd-window).
Something like this would do the job
@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
Here is a simple hybrid batch/JScript script that I think will do what you want.
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();
Usage:
yourCommand | show3
The script could be simplified to pure JScript, but then it won't be as convenient to use:
show3.js
while( !WScript.StdIn.AtEndOfStream ) {
WScript.StdOut.Write( '\x08\x08\x08' + WScript.StdIn.ReadLine().substr(0,3) );
}
WScript.StdOut.WriteLine();
Usage:
yourCommand | cscript //nologo show3.js
EDIT As jeb commented, you should not need any redist to use this solution.
I've taken some of the concepts in jeb's answer and combined the entire process into one hybrid script. No need for a standalone "show3" file.
@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 would be whatever compression command you are using. Based on your comments, it sounds like you might have to use yourCommand 2>&1 if the output you want is printing to stderr instead of stdout.
I've created a "yourCommand.bat" file for testing purposes. It crudely emulates the output behavior you describe for your compression program.
@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
)
Finally, if you really want a pure batch solution, I greatly simplified jeb's solution. I eliminated the temp file and used a pipe instead.
@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
Edit - I modified the EOF test to ignore any leading or trailing spaces. This should make the code more robust.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With