Solved Batch file to find the last occurrence of a string?

December 3, 2016 at 10:18:37
Specs: Windows 7, I7/16GB
I'm trying to set a variable and write to a file the value of the last occurrence of 'time=', 00:24:53.16, in this example file.

-------- file: input.txt --------
Input #0, mp3, from 'test.mp3':
Metadata:
encoder : Lavf57.51.102
Duration: 00:23:41.31, start: 0.025057, bitrate: 128 kb/s
Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p, 128 kb/s
Metadata:
encoder : Lavc57.60
Output #0, null, to 'pipe:':
Metadata:
encoder : Lavf57.51.102
Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s
Metadata:
encoder : Lavc57.60.101 pcm_s16le
Stream mapping:
Stream #0:0 -> #0:0 (mp3 (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
size=N/A time=00:03:29.65 bitrate=N/A speed= 419x
size=N/A time=00:07:56.65 bitrate=N/A speed= 477x
size=N/A time=00:12:25.43 bitrate=N/A speed= 497x
size=N/A time=00:16:56.45 bitrate=N/A speed= 508x
size=N/A time=00:21:22.56 bitrate=N/A speed= 513x
size=N/A time=00:24:53.16 bitrate=N/A speed= 515x
video:0kB audio:25720kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
-------- end of file ------------

The trouble I'm having comes from the fact that all the 'lines' starting with 'size=' (except the last one) end with <sp><sp><sp><sp><cr>, no <lf>, so they are really part of a single line as far a parse-ability is concerned. The last 'size=' line has a <cr><lf>.

So, the problem really boils down to extracting the last of several occurrences of a string in a line of unknown length, e.g.:

size=N/A time=00:03:29.65 bitrate=N/A speed= 419x size=N/A time=00:07:56.65 bitrate=N/A speed= 477x size=N/A time=00:12:25.43 bitrate=N/A speed= 497x size=N/A time=00:16:56.45 bitrate=N/A speed= 508x size=N/A time=00:21:22.56 bitrate=N/A speed= 513x size=N/A time=00:24:53.16 bitrate=N/A speed= 515x

In case it makes the solution any easier, the desired 'time=' value will always be the last one in the file, and will always be the 'largest'.

The following batch file almost works, but it finds and processes the first 'time=' value, not the last. It converts the value to seconds, strips the echo-added <cr><lf>, sets an environment variable, and sends the result to a file. It works except on the wrong data. Is there some way to accomplish this in a pure Win batch file?

@echo off
for /F "tokens=1-7 delims==:. " %%1 in (input.txt) do (if "%%1"=="size" call :findtime %%4 %%5 %%6 %%7)
:findtime
echo:
set /A s=%3 & set /A s=s+%2*60 & set /A s=s+%1*60*60
echo:%1:%2:%3.%4 = %s%.%4 seconds
set dur=%s%.%4
echo:%dur% = includes a CRLF
<nul (set/p z=%dur%)
echo: = stripped CRLF, method1
(echo:|set /p ="%dur%")>duration.txt %= strip CRLF then send to file for later use =%
type duration.txt
echo: = stripped CRLF, method2
echo:
pause


See More: Batch file to find the last occurrence of a string?

Report •

✔ Best Answer
December 4, 2016 at 17:13:55
::====== script starts here ===============
:: get last instance of time=nnnnn
:: lasttime.bat 2016-12-04 15:44:02.71
@echo off & setLocal enableDELAYedeXpansioN

:main
for /f "tokens=* delims= " %%a in ('find "time=" ^< input.txt') do (
set S=%%a
)
call :sub1 !S!
echo V is set to !V!
goto :eof

:sub1
for %%i in (%*) do (
:loop1
if %1 equ time set V=%1=%2
if "%2" neq "" SHIFT && goto :loop1
)
goto :eof
::====== script ends here =================

=====================

M2 Get custom script or take private lessons



#1
December 3, 2016 at 19:08:20
Here's an initial stab. I can't recall offhand what the limit of the number of commandline parms is, so this might be screwed off the bat for long sequences. It worked on your sample, but you know how that goes...
::--------- begin script attempt 'tt.bat'
@echo off & setlocal
for /f "tokens=*" %%a in ('find /i "size="^<tt') do call :xx %%a
echo %z%
goto :eof

:xx
shift
shift
shift
rem echo %1
if "%1" equ "" goto :eof
set z=%1
shift
shift
shift
shift
shift
goto :xx
:: --------- end script
There are other feasible solutions, this just came first in my muddled head.


Report •

#2
December 4, 2016 at 00:51:55
Maybe I'm missing the plot.

::====== script starts here ===============
:: get last instance of time=nnnnn
:: lasttime.bat 2016-12-04 15:44:02.71
@echo off > NEWFILE & setLocal enableDELAYedeXpansioN

:main
for /f "tokens=2 delims= " %%a in ('find "time=" ^< input.txt') do (
set V=%%a
)
echo V is set to !V!
goto :eof
::====== script ends here =================

=====================

M2 Get custom script or take private lessons


Report •

#3
December 4, 2016 at 06:40:26
Thanks nbrane. I'd like to give your script a try. Sorry if I'm missing something, but where does the script call up the data file?

Thanks as well, Mechanix2go. The value I'm looking for is the last occurrence of the token 'time=' given in the input file. Your script finds the first.


Report •

Related Solutions

#4
December 4, 2016 at 07:36:14
"Your script finds the first."

Not on my box

=====================

M2 Get custom script or take private lessons


Report •

#5
December 4, 2016 at 08:11:24
@Mechanix2go:

The <sp><sp><sp><sp><cr> was replaced with <cr><lf> somewhere along the line when I copied/pasted/posted the file contents. Your script indeed does find the last line in that case.

How can I post something that won't get converted so you have the correct input to work with?

Othewise, maybe the following could be used as input.txt:

the first of several lines before the relevent section.
size=N/A time=00:03:29.65 bitrate=N/A speed= 419x size=N/A time=00:07:56.65 bitrate=N/A speed= 477x size=N/A time=00:12:25.43 bitrate=N/A speed= 497x size=N/A time=00:16:56.45 bitrate=N/A speed= 508x size=N/A time=00:21:22.56 bitrate=N/A speed= 513x size=N/A time=00:24:53.16 bitrate=N/A speed= 515x
the last line


Report •

#6
December 4, 2016 at 08:46:08
Zip up your file & send it to the address on my site:

http://www.golden-triangle.com/Mech...

=====================

M2 Get custom script or take private lessons


Report •

#7
December 4, 2016 at 17:13:55
✔ Best Answer
::====== script starts here ===============
:: get last instance of time=nnnnn
:: lasttime.bat 2016-12-04 15:44:02.71
@echo off & setLocal enableDELAYedeXpansioN

:main
for /f "tokens=* delims= " %%a in ('find "time=" ^< input.txt') do (
set S=%%a
)
call :sub1 !S!
echo V is set to !V!
goto :eof

:sub1
for %%i in (%*) do (
:loop1
if %1 equ time set V=%1=%2
if "%2" neq "" SHIFT && goto :loop1
)
goto :eof
::====== script ends here =================

=====================

M2 Get custom script or take private lessons


Report •

#8
December 4, 2016 at 19:28:34
First, sorry, I used 'tt' instead of input.txt in my first submission.

I swapped all the CR/LFs to CRs This code tries two different methods applied to the CR-only version of 'INPUT.TXT', and seems to work with both:
@echo off & setlocal
echo method one:
for /f "tokens=*" %%a in ('find /i "size="^<input.txt') do call :xx %%a
echo method two:
for /f "tokens=*" %%a in ('find /i "size="^<input.txt') do call :aa "%%a"
goto :eof

:xx
shift
shift
shift

if "%1" equ "" goto :report
set z=%1
shift
shift
shift
shift
shift
goto :xx

:aa
set t=%~1
:bb
set z=%t:~14,11%
set t=%t:~50%
if defined t goto :bb

:report
echo last timestamp: %z%

@M2: much better approach. I knew I was missing something that would work better. Too fogged to see it and my gps on the blink!

message edited by nbrane


Report •

#9
December 5, 2016 at 08:00:10
@Mechanix2go
Your script works perfectly with everything I've tried it with. This will allow me to do things I've been unable to do with the files I'm working with. Thanks much for your input.

Report •

#10
December 5, 2016 at 08:46:46
@nbrane
Your script works well on almost all of the files I've tried it on. I've since discovered that some files have a different format than I initially identified which unfortunately won't parse the same.

Instead of "size=N/A time=00:03:06.46 bitrate=N/A speed= 442x" they look like "frame= 721 fps=509 q=-0.0 Lsize=N/A time=00:02:24.20 bitrate=N/A speed= 102x".

I do appreciate the method you used and will be able to make good use of it with slight modifications in another application I have. Thanks much.


Report •

#11
December 8, 2016 at 07:53:39
Hi nbrane,

You were wondering what the limit on params / SHIFTs might be.
So was I so I messed around with it.
The short answer is, as Tonto would say, many.
22:52 2016-12-08
::====== script starts here ===============
:: test how many command line parameters work
:: 22:52 2016-12-08
@echo off & setLocal enableDELAYedeXpansioN

:main
for /L %%a in (1 1 1024) do (
set S=!S! %%a
)
call :sub1 !S!
goto :eof

:sub1
for %%i in (%*) do (
:loop1
set V=%1
if "%2" neq "" SHIFT && goto :loop1
)
set V
goto :eof
::====== script ends here =================

=====================

M2 Get custom script or take private lessons


Report •

Ask Question