Discussion forum for all Windows batch related topics.
Moderator: DosItHelp
-
SIMMS7400
- Posts: 546
- Joined: 07 Jan 2016 07:47
#1
Post
by SIMMS7400 » 12 Mar 2020 18:50
Hello Folks -
I have a output file that I need to parse. The output file consists of this:
outbox/logs/DIM_BPMC_PLN - Account_292.log
outbox/logs/DIM_BPMC_PLN - Account_287.log
outbox/logs/DIM_BPMC_PLN - Account_285.log
outbox/logs/DIM_BPMC_PLN - Account_284.log
outbox/logs/Account Reconciliation Manager_481.log
outbox/logs/Account_Reconciliation_Manager_481.log
outbox/logs/DIM_REGEN - Custom_2080.log
outbox/logs/DIM_REGEN - Custom_2079.log
outbox/logs/DIM_BPMC_PLN - Account_207.log
outbox/logs/DIM_BPMC_PLN - Account_206.log
Test_test_test.txt
Test test test.txt
Test1_2_3 4.txt
Testing_808.txt
Test55.txt
Test5_600.txt
Test_Test.zip
Test2.zip
Test 4.zip
Test10 11_12.zip
What I need to do is return the line in the file that start with 'outbox/logs/' that has the highest number suffixed to the name. FOr instance, the code should return the following line:
outbox/logs/DIM_REGEN - Custom_2080.log
This can be done very easily in powershell but wondering if it's easy enough in batch? Thanks!
-
Hackoo
- Posts: 103
- Joined: 15 Apr 2014 17:59
#2
Post
by Hackoo » 12 Mar 2020 20:07
With your example that you provide, this batch script may be did the trick
Code: Select all
@echo off
Title Get line with highest numerical string
Set "InputFile=%1"
If "%~x1" NEQ ".txt" Goto :Help
Set "OutPutFile=%~dp0OutPutFile.txt"
If Exist "%OutPutFile%" Del "%OutPutFile%"
@for /f "tokens=* delims=" %%a in ('Type %InputFile% ^|find /I "outbox" ^|sort') do set "LastLine=%%a"
If defined LastLine (
Color 0A & Mode 80,3 & echo(
echo %LastLine%>%OutPutFile%
echo %LastLine%
Timeout /T 2 /nobreak>nul
Start "" "%OutPutFile%" & Exit
) Else (
Color 0C & Mode 80,3 & echo(
echo Nothing to parse into this file "%InputFile%"
Timeout /T 3 /nobreak>nul & Exit
)
::------------------------------------------------------------------
:Help
Color 0C & Mode 80,3
echo(
echo Usage : Drag and Drop a txt file over this script:"%~nx0"
Timeout /T 5 /nobreak>nul & Exit
::------------------------------------------------------------------
-
SIMMS7400
- Posts: 546
- Joined: 07 Jan 2016 07:47
#3
Post
by SIMMS7400 » 13 Mar 2020 01:49
Thank you Hackadoo.
Unfortunately, I don't think it's fail proof. if I add this line to the file:
outbox/logs/DIM_BPMC_PLN - Account_2082.log
It doesn't return it. Furthermore, if I add "7898574" to a file name, it doesn't pull that either.
outbox/logs/DIM_BPMC_PLN - Account_7898574.log
-
Aacini
- Expert
- Posts: 1914
- Joined: 06 Dec 2011 22:15
- Location: México City, México
-
Contact:
#4
Post
by Aacini » 13 Mar 2020 02:00
This works:
Code: Select all
@echo off
setlocal EnableDelayedExpansion
set lastNum=0
for /F "delims=" %%a in ('findstr "outbox/logs/" test.txt') do (
set "a=%%~Na"
for %%b in ("!a:_=.!") do set "num=%%~Xb"
if !num:~1! gtr !lastNum! set "lastNum=!num:~1!" & set "lastLine=%%a"
)
echo %lastLine%
-
dbenham
- Expert
- Posts: 2461
- Joined: 12 Feb 2011 21:02
- Location: United States (east coast)
#5
Post
by dbenham » 13 Mar 2020 19:08
It wouldn't be hard to write a custom JScript or VBScript solution.
I went ahead and developed a
JREPL.BAT solution - it is significantly faster than any pure batch solution once the input becomes "large".
I used line continuation just to make it easier to read.
Code: Select all
jrepl "^outbox/logs/.*?(\d+)\.log$"^
"$txt=false;num=parseInt($1);if (num>max){max=num;str=$src}"^
/jbeg "var max=0,str='',num" /jend "stdout.writeLine(str)" /jmatchq /f test.txt
Dave Benham
-
siberia-man
- Posts: 208
- Joined: 26 Dec 2013 09:28
-
Contact:
#6
Post
by siberia-man » 14 Mar 2020 19:15
Also (in addition to dbeham's suggestion) the
wsx tool can help you to get the required result:
Code: Select all
wsx /n /e:"m=LINE.match(/^outbox\/logs\/.*?(\d+)\.log$/)||next();n=Number(m[1]);if(n>max){max=n;str=LINE}" /begin:"str='';max=0" /end:"echo(str)" test.txt
Code: Select all
wsx /n /e:"m=LINE.match(/^outbox\/logs\/.*?(\d+)\.log$/)||next();n=Number(m[1]);if(n>max){max=n;str=LINE}" /let:str= /let:max=0 /end:"echo(str)" test.txt
-
SIMMS7400
- Posts: 546
- Joined: 07 Jan 2016 07:47
#7
Post
by SIMMS7400 » 22 Mar 2020 03:11
Thank you, all!!
I reallly Aacini's and Dave's solutions and I am going to leverage both. The file to scan will only be about 200 lines max, give or take a few.
Thank you again and I hope everyone is healthy!
-
SIMMS7400
- Posts: 546
- Joined: 07 Jan 2016 07:47
#8
Post
by SIMMS7400 » 30 Jul 2020 08:17
HI AAcini -
I just wanted to say thank you again for your solution, it's working great! I am running into once issue. There are times when there is another string between the numerical portion and the .log, which I don't want to factor into the logic.
Is there a way to ignore those instances?
Code: Select all
outbox/logs/Planning_472.log
outbox/logs/Planning_472.pbcs.log
outbox/logs/Planning_473.log
outbox/logs/Planning_474.log
outbox/logs/Planning_475.log
outbox/logs/Planning_476.log
outbox/logs/Planning_477.log
outbox/logs/Planning_481.log
outbox/logs/Planning_482.log
outbox/logs/Planning_483.log
outbox/logs/Planning_484.log
outbox/logs/Planning_485.log
outbox/logs/Planning_486.log
outbox/logs/Planning_487.log
outbox/logs/Planning_488.log
outbox/logs/Planning_501.log
And it may not always be pbcs, I need to make that dynamic where if ANY string is between the numerical portion and .log, to ignore those lines.
Thanks!
-
SIMMS7400
- Posts: 546
- Joined: 07 Jan 2016 07:47
#9
Post
by SIMMS7400 » 30 Jul 2020 08:42
THis works:
Code: Select all
for /F "delims=" %%a in ('findstr "outbox/logs/" test.txt ^|FINDSTR /V ".pbcs.log"')
But I need to make the "pbcs" part more generic...It could be any non-numerical string here. THis seems to work with my test, but is it best practice based on my business need?
Code: Select all
for /F "delims=" %%a in ('findstr "outbox/logs/" test.txt ^|FINDSTR /R "[0-9].log"')
-
Squashman
- Expert
- Posts: 4486
- Joined: 23 Dec 2011 13:59
#10
Post
by Squashman » 30 Jul 2020 17:07
SIMMS7400 wrote: ↑30 Jul 2020 08:42
But I need to make the "pbcs" part more generic...It could be any non-numerical string here. THis seems to work with my test, but is it best practice based on my business need?
Code: Select all
for /F "delims=" %%a in ('findstr "outbox/logs/" test.txt ^|FINDSTR /R "[0-9].log"')
The period means match a single character. You want a literal period match.
So if you happened to read the documentation for the FINDSTR command.
Code: Select all
Regular expression quick reference:
. Wildcard: any character
* Repeat: zero or more occurrences of previous character or class
^ Line position: beginning of line
$ Line position: end of line
[class] Character class: any one character in set
\x Escape: literal use of metacharacter x
You can use the Character class and an asterisk to match more than one number. You then want to match a literal period so you have to escape the period with backslash because the period is wildcard.
Code: Select all
for /F "delims=" %%a in ('findstr "outbox/logs/" test.txt ^|FINDSTR /R "[0-9]*\.log"')
-
SIMMS7400
- Posts: 546
- Joined: 07 Jan 2016 07:47
#11
Post
by SIMMS7400 » 31 Jul 2020 03:13
HI Squash -
When leveraging your suggestion, it does not yield the correct results.
Squashman wrote: ↑30 Jul 2020 17:07
SIMMS7400 wrote: ↑30 Jul 2020 08:42
But I need to make the "pbcs" part more generic...It could be any non-numerical string here. THis seems to work with my test, but is it best practice based on my business need?
Code: Select all
for /F "delims=" %%a in ('findstr "outbox/logs/" test.txt ^|FINDSTR /R "[0-9].log"')
The period means match a single character. You want a literal period match.
So if you happened to read the documentation for the FINDSTR command.
Code: Select all
Regular expression quick reference:
. Wildcard: any character
* Repeat: zero or more occurrences of previous character or class
^ Line position: beginning of line
$ Line position: end of line
[class] Character class: any one character in set
\x Escape: literal use of metacharacter x
You can use the Character class and an asterisk to match more than one number. You then want to match a literal period so you have to escape the period with backslash because the period is wildcard.
Code: Select all
for /F "delims=" %%a in ('findstr "outbox/logs/" test.txt ^|FINDSTR /R "[0-9]*\.log"')
-
Aacini
- Expert
- Posts: 1914
- Joined: 06 Dec 2011 22:15
- Location: México City, México
-
Contact:
#12
Post
by Aacini » 31 Jul 2020 23:17
I think this do the trick:
Code: Select all
@echo off
setlocal EnableDelayedExpansion
set lastNum=0
for /F "delims=" %%a in ('findstr "outbox/logs/.*[0-9]\.log" test.txt') do (
set "a=%%~Na"
for %%b in ("!a:_=.!") do set "num=%%~Xb"
if !num:~1! gtr !lastNum! set "lastNum=!num:~1!" & set "lastLine=%%a"
)
echo %lastLine%
Antonio
-
SIMMS7400
- Posts: 546
- Joined: 07 Jan 2016 07:47
#13
Post
by SIMMS7400 » 01 Aug 2020 03:14
HI Antonio -
That did the trick, thank you so much!!!