Batch to parse lines containing a specific string from an input file - batch-file

Edit: yes, this has to be done in batch.
I need to be able to read an input file, and parse out certain sections only of lines that contain a specific string, then write that to an output file. For example:
input =
i_NumberOfPersonInTheDataBase=1
i_NumberOfPersonInTheDataBase < 50 AdjTotal=801
MATCH IdentificationResult id=Olivier Score=11419 (NOT_DEFINED-cfv )
02-11-11-07-00 TAG_CAPTURE Badge:CAPTURE - Candidate Found :Olivier
i_NumberOfPersonInTheDataBase=1
i_NumberOfPersonInTheDataBase < 50 AdjTotal=801
MATCH IdentificationResult id=Martin Score=1008 (NOT_DEFINED-cfv )
02-11-11-08-15 TAG_CAPTURE Badge:CAPTURE - Candidate Found :Martin
in lines that contain the string "IdentificationResult", I need to return the strings that contain the id and Score.
expected output =
id=Olivier Score=11419
id=Martin Score=1008
This is what I have so far:
#setlocal enableextensions enabledelayedexpansion
:: Path of input and output files
set INPUTFILE=DemoFingerOtf-2.log
set OUTPUTFILE=logOutput.txt
:: Clear out the output file
#echo on > %OUTPUTFILE%
:: Read %INPUTFILE% and loop through each line
for /F "tokens=* delims=" %%A in (%INPUTFILE%) do (
SET my_line=%%A
SET my_line=!my_line:IdentificationResult=!
if not !my_line!==%%A (
call :parse_it
)
)
:parse_it
for /F "usebackq tokens=1,2,3,4 delims=~" %%1 in ('%my_line: =~%') do (
echo %%3 %%4>> %OUTPUTFILE%
)
The problem I have right now is that when I run this script, I get a ') was unexpected at this time error. When I remove the parentheses from the input, I get my expected results. I've tried including a line like the following to remove the parentheses:
:: Read %INPUTFILE% and loop through each line
for /F "tokens=* delims=" %%A in (%INPUTFILE%) do (
SET my_line=%%A
SET my_line=!my_line:IdentificationResult=!
if not !my_line!==%%A (
SET new_line=%my_line:~0,-18%
call :parse_it
)
)
:parse_it
for /F "usebackq tokens=1,2,3,4 delims=~" %%1 in ('%new_line: =~%') do (
echo %%3 %%4>> %OUTPUTFILE%
)
I know that in the lines I want, the section with parentheses will always be exactly 18 characters, so I trim them from the end. However, when I do that, for some reason I get the following as my output:
wrong output:
id=Olivier Score=11419
id=Olivier Score=11419
id=Olivier Score=11419
So, I'm getting only the data from the first line that I want to parse, and I'm getting it three times (even though there are only two lines in my input that meet my criteria). Why am I getting this data multiple times instead of the correct data? Additionally, is there a better way around the ') was unexpected at this time error that I was getting?

Edit modificated without trailing space. Without "ScoreAdjustment" and work with "John Smith" :)
echo off
:: Path of input and output files
set INPUTFILE=DemoFingerOtf-2.log
set OUTPUTFILE=logOutput.txt
setlocal enabledelayedexpansion
for /f "tokens=2,3 delims=^=^(" %%a in ('type "%INPUTFILE%" ^| find /i "IdentificationResult"') do (
set $line=Id=%%a=%%b
set $line=!$line:ScoreAdjustment=!
set $line=!$line:~0,-1!
echo !$line!>>%OUTPUTFILE%)
Endlocal

#ECHO OFF &SETLOCAL
for /f "delims=" %%a in ('^<file find "IdentificationResult"') do call:DOit "%%~a"
goto:Eof
:doit
setlocal
set "string=%~1"
set "STring=%string:*IdentificationResult=%"
for /f "Tokens=1,2" %%b in ("%string%") do echo(%%b %%c
exit /b

The easy way:
if not !my_line!==%%A (
ECHO !my_line:~7,-19!>> %OUTPUTFILE%
)
A few issues with your code, but I applaud your effort to solve the problem.
Batch doesn't stop at a label - they're just markers, so it charges straight through, hence you'd need a
goto :eof
before any suboutine label.
You can't use numerics as metavariables, so in parse_it you'd need a letter, not 1. You can also use space as a delims character - but it must be specified as the last delimiter (ie. just before the closing "
So parse_it could be reduced (if it was required) to
for /F "tokens=1* delims= " %%q in ("%new_line%") do (
echo %%r>> %OUTPUTFILE%
)
But - overall, bravo for the attempt!

You dont say what language you want. so can you do something like:
grep IdentificationResult file | awk '{ print $3, $4}' > output.file

Related

How to get records right arranged in windows batch?

I have file s_result.txt as:
AAA,BBB,CCC
DDD,EEE
FFF,GGG
HHH,III,JJJ
...
And I try to get the sf_result.txt like this:
AAA,BBB
AAA,CCC
DDD,EEE
FFF,GGG
HHH,III
HHH,JJJ
...
I used script as below:
REM Transfer s_result.txt to sf_result.txt
DEL sf_result.txt
Echo. 2>sf_result.txt
for /F "tokens=1,2,3 delims=," %%a in (s_result.txt) do (
If %%c EQU [] (
ECHO %%a,%%b>>sf_result.txt
) else (
ECHO %%a,%%b>>sf_result.txt
ECHO %%a,%%c>>sf_result.txt
)
)
I got this result.txt instead:
AAA,BBB
AAA,CCC
DDD,EEE
DDD,
FFF,GGG
FFF,
HHH,III
HHH,JJJ
...
How can I get the right result?
Thanks,
If you want to parse line-by-line, use for /F. If you want to tokenize word-by-word on a single line, use for without the /F. Also, in a basic for loop, Windows already tokenizes on unquoted commas with no need to specify a delimiter. (It also tokenizes on spaces, tabs, and semicolons.) With this in mind, the solution is actually pretty simple.
#echo off & setlocal
for /f "usebackq tokens=1* delims=," %%I in ("test.txt") do (
for %%x in (%%J) do (
echo(%%I,%%x
)
)
Output:
AAA,BBB
AAA,CCC
DDD,EEE
FFF,GGG
HHH,III
HHH,JJJ
There have already been great answers provided with some smart approaches.
However, I want to stick to the code you posted here.
The main problem is the line if %%c EQU [], because it compares the third token with the literal string []; the third token can be CCC, JJJ, or an empty string, according to your example, so the condition is never going to be fulfilled.
To correct that, you should write if "%%c"=="" instead.
You could further improve your script by doing a single redirection > to the output file rather than creating it in advance and appending multiple times; just put the entire for /F loop in between parentheses and redirect the whole block.
So here is the corrected and improved code:
rem Transfer s_result.txt to sf_result.txt
> "sf_result.txt" (
for /F "usebackq tokens=1-3 delims=," %%a in ("s_result.txt") do #(
if "%%c"=="" (
echo %%a,%%b
) else (
echo %%a,%%b
echo %%a,%%c
)
)
)
The # symbol prevents command echoes of the loop body to be written to the output file as well. If there is #echo off placed at the beginning of your script you do no longer need that symbol.
Of course this code cannot handle lines with more than three tokens correctly.
I do like rojos clever approach (+1).
To overcome the implications he mentions I think of a recursive approach.
:: Q:\Test\2018\06\28\SO_51073893.cmd
#echo off & setlocal
for /f "usebackq tokens=1-2* delims=," %%A in ("test.txt") do Call :Sub "%%A" "%%B" "%%C"
Goto :Eof
:Sub
Echo %~1,%~2
if "%~3" neq "" for /f "tokens=1* delims=," %%D in (%3) do Call :Sub %1 "%%D" "%%E"
With a slightly changed file test.txt I get this output:
> SO_51073893.cmd
AAA,B=B
AAA,C;C
DDD,EEE
FFF,GGG
HHH,I I
HHH,JJJ

Using if conditions at the end of a FOR loop in Batch

I have a simple for loop in a batch file I'm working on but I can't get the variables to expand correctly. the whole script is below..
setlocal enabledelayedexpansion
set track=0
FOR /f "tokens=2" %%G IN ('find "PhysicalTrackNumber" %1') DO if %track% LSS %%G set track=%%G
echo %track%
echo %1
pause
The for command pulls all the rows with the physical track number and I'm just trying to get the biggest number. IT always stays 0 though when it's comparing. I've tried with !! around my variable as well but then the script seems to do something completely different. I thought it would take the new variable.
What am I missing to compare the outputs to the previous and just get the biggest number?
find "string" filename output consists of
an empty line;
a string of 10 dashes followed by the filename being searched line;
any matching lines of text in the file.
Use skip=2 option (a number of lines to skip at the beginning):
FOR /f "skip=2 tokens=2" %%G IN ('find "PhysicalTrackNumber" "%~1"') DO (
if !track! LSS %%G set "track=%%~G"
)
As an alternative, use findstr instead of find:
FOR /f "tokens=2" %%G IN ('findstr "PhysicalTrackNumber" "%~1"') DO (
if !track! LSS %%G set "track=%%~G"
)

How to randomly rearrange lines in a text file using a batch file

I am creating a code that strips through different MAC addresses randomly, but cannot figure out how to do this. My thought on how to approach this is to randomize or rearrange the order of the MAC address in the text file with this script, but I cannot figure out how to do this with a batch file. How this will work is that it will read "maclist.txt", then create a new temp file with the random order "maclist_temp.txt", that will be the rearranged file. Then, it will pull this randomized file in order.
I have tried Google and searching the web, but I haven't found anything too useful. I'm still actively looking, but any advice would be extremely useful.
Something as simple as extracting and deleting a random line and then adding to the bottom might work. Randomization would be better though, but I want to keep the original list. Something like:
Make a temp copy of maclist.txt called maclist_temp.txt
Take one random MAC address, remove it from maclist_temp.txt
Readd it to the bottom
That is all I want, but any suggestions are welcome.
You may try this batch file to help you to shuffle your maclist.txt. The usage of the batch code is
C:\> type list.txt | shuffle.bat > maclist_temp.txt
Here are the contents of shuffle.bat:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET TmpFile=tmp%RANDOM%%RANDOM%.tmp
TYPE NUL >%Tmpfile%
FOR /F "tokens=*" %%i IN ('MORE') DO SET Key=!RANDOM!!RANDOM!!RANDOM!000000000000& ECHO !Key:~0,15!%%i>> %TmpFile%
FOR /F "tokens=*" %%i IN ('TYPE %TmpFile% ^| SORT') DO SET Line=%%i&ECHO.!Line:~15!
::DEL %TmpFile%
ENDLOCAL
After issuing the above command, maclist_temp.txt will contain a randomized list of MAC addresses.
Hope this helps.
Here is a simpler method to randomize/randomise a file, no temp files needed. You can even reuse the same input filename.
Limitations are: blank lines and line starting with ; will be skipped, and lines starting with = will have all leading = signs stripped and ^ characters are doubled.
#echo off
setlocal
for /f "delims=" %%a in (maclist.txt) do call set "$$%%random%%=%%a"
(for /f "tokens=1,* delims==" %%a in ('set $$') do echo(%%b)>newmaclist.txt
endlocal
I really like foxidrive's approach. Nevertheless I want to provide a solution with all the listed limitations eliminated (although cmd-related restrictions like file sizes < 2 GiB and line lengths < ~ 8 KiB remain).
The key is delayed expansion which needs to be toggled to not lose explamation marks. This solves all the potential problems with special characters like ^, &, %, !, (, ), <, >, | and ".
The counter index has been implemented in order not to lose a single line of the original text file, which could happen without, because random may return duplicate values; with index appended, the resulting variable names $$!random!.!index! are unique.
The findstr /N /R "^" command precedes every line of the original file with a line number followed by a colon. So no line appears empty to the for /F loop which would ignore such. The line number also implicitly solves the issue with leading semicolons, the default eol character of for /F.
Finally, everything up to and including the first colon (remember the said prefix added by findstr) is removed from every line before being output, hence no more leading equal-to signs are dismissed.
So here is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set /A "index=0"
for /f "delims=" %%a in ('findstr /N /R "^" "%~dpn0.lst"') do (
setlocal EnableDelayedExpansion
for /F %%b in ("$$!random!.!index!") do (
endlocal
set "%%b=%%a"
)
set /A "index+=1"
)
> "%~dpn0.new" (
for /f "delims=" %%a in ('set $$') do (
set "item=%%a"
setlocal EnableDelayedExpansion
echo(!item:*:=!
endlocal
)
)
endlocal
exit /B
This seems to work. Feed it a command line parameter of the file to randomize.
#echo off
setlocal EnableDelayedExpansion
rem read the number of lines in the file
rem the find prepends the line number so we catch blank lines
for /f "delims=" %%n in ('find /c /v "" %1') do set "len=%%n"
set len=!len:*: =!
rem echo %1 has %len% lines
rem Relocate as many lines as there are lines in the file
for /l %%j in (1 1 !len!) do (
rem echo starting round %%j
rem geta random number between 1 and the number of lines in the file
set /a var=!random! %% !len! + 1
rem echo relocating line !var!
rem make sure there is no temp file
if exist %1.temp del %1.temp
rem read each line of the file, write any that don't match and then write the one that does
<%1 (
for /l %%i in (1 1 !len!) do (
rem if it is the target line then save it
if %%i == !var! (
set /p found=
rem echo saving !found!
)
rem if it is the target line then write it
if not %%i == !var! (
set /p other=
rem echo writing !other!
echo !other!>> %1.temp
)
)
rem now write the target line at the end
rem echo appending !found!
echo !found!>> %1.temp
)
rem replace the original with the temp version
move %1.temp %1>nul
)
rem print the result
type %1
Place in cmd file
for /f "tokens=2 delims=/" %%m in ('cmd /e:on /v:on /c "for /f %%f in (maclist.txt) do #echo !random!/%%f" ^| sort') do echo %%m
It spawns a cmd which reads the mac list in the inner for, prefixes a random value and a slash to the mac and sorts the list. Then this list is splitted in the outter for using the slash as delimiter and printing the mac address.

Remove a number of delimiters from each line of file

I have a file which I need to load into a database. It has a delimiter of pipe (|) however each line contains different number of pipes. Using a batch script, how can I remove pipes from each line so the same number of pipes are on each line?
Example of file:
1|2|3||||||
4|5|6|||
7|8||||||
Let's say I'd like 5 pipes on each line only so it looks like:
1|2|3|||
4|5|6|||
7|8||||
Update See second solution and limitation updates.
Example file.txt contents
A|B|C|D|E|F|G
1|2|3|4|5|6|7
!|#|#|$|%|^|&
]1|]2|]3|]4|]5|]6|]7
|Two||Four||||Eight
!#$%^&%^*(){}|[]';/.,<>/|
Lonely||||||||||||||||||
Sep|er|ate| From| Th|e |W||orld | |
First Solution
Here is a simple way to do what you want. It should not have any problems with special characters.
Limitations
It only supports up to 24 25 columns as it is currently written. %%A to %%Y
The first value may not begin with ]. Replaced for /F "tokens=1,* delims=]" %%Y in ('type file.txt ^| find /v /n ""') do ( with for /F "delims=" %%Z in ('type file.txt') do (.
"Empty" fields may only appear at the end of every line. See second solution.
Does not preserve blank lines in the file. (This can be fixed if desired.)
Just specify how many and which columns you want to keep. For example tokens=3-5,12,48-50 will select only columns 3,4,5,12,48,49,50. Make sure you add on or remove the variables to match the output you want. echo %%A^|%%B^|%%D^|%%C^|%%G^|%%E^|%%F. Note that the columns can be reordered as well in the echo statement.
#echo off
setlocal DisableDelayedExpansion
for /F "delims=" %%Z in ('type file.txt') do (
for /F "tokens=1-5 delims=|" %%A in ("%%Z") do (
echo %%A^|%%B^|%%C^|%%D^|%%E
)
)
endlocal
pause >nul
You can either redirect the output of the .bat file into a new file Script.bat>output.txt or output the echo command to a file by appending >>output.txt to the echo line.
Example Output:
A|B|C|D|E
1|2|3|4|5
!|#|#|$|%
]1|]2|]3|]4|]5
Two|Four|Eight|| <-- Note that this line exhibits limit 3.
!#$%^&%^*(){}|[]';/.,<>/|||
Lonely||||
Sep|er|ate| From| Th
Second Solution
Shares only limitations 1 and 4. Currently adds spaces into existing blank columns to preserve all columns. They can be removed with a further code change, but will not add unless desired by the OP.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%Z in ('type file.txt') do (
set "xLine=|%%Z"
call :Parse xLine
)
endlocal
pause >nul
goto :eof
:Parse
call set "xLine=%%%~1:||=| |%%"
for /F "tokens=1-5 delims=|" %%A in ("%xLine%") do (
echo %%A^|%%B^|%%C^|%%D^|%%E
)
goto :eof
Example Output:
A|B|C|D|E
1|2|3|4|5
!|#|#|$|%
]1|]2|]3|]4|]5
|Two| |Four|
!#$%^&%^*(){}|[]';/.,<>/|||
Lonely| | | |
Sep|er|ate| From| Th
There is no direct way to achieve this process, so each character must be revised in order to count the number of pipes in each line. It works, but it is somewhat slow.
#echo off
setlocal EnableDelayedExpansion
rem Number of desired pipes
set limit=5
for /F "delims=" %%a in (input.txt) do (
set "line=%%a"
rem Get position of last character
set last=0
for /L %%b in (12,-1,0) do (
set /A "last|=1<<%%b"
for %%c in (!last!) do if "!line:~%%c,1!" equ "" set /A "last&=~1<<%%b"
)
rem Copy each character to result, but just %limit% number of pipes
set pipes=0
set result=
for /L %%c in (0,1,!last!) do (
if "!line:~%%c,1!" neq "|" (
set "result=!result!!line:~%%c,1!"
) else (
set /A pipes+=1
if !pipes! leq %limit% set "result=!result!|"
)
)
echo !result!
)
Previous program will fail if the input line contain exclamation marks.
Output:
1|2|3|||
4|5|6|||
7|8||||
Antonio

How to find a string and replace part of it using batch commands?

I have text file with lot of parameters with unique names. I need to find a parameter by its name and change the value of the parameter. The file looks something like this
ID Value Name
4450 2.0 / [var_pot] 'DCF_loc'
4451 100.0 / [var] 'DCF_t'
4452 0.1 / [var] 'DCF_dur'
4458 1000.0 / [var] 'CommtF_t_P1'
For e.g. I need to find the parameter 'DCF_t' in the file and replace its value from 100 to some other value say 10. Unfortunately in my case, only the names and values of the parameters are in my control. I am in need of a batch file to do the "find and replace" job.
Please help me out...Thanks in advance...
in case it is Windows, you need to
loop over all the lines of the file. try something like.. FOR /F %%a in (values.txt) DO echo %%a
skip the first header line. Try FOR /f "skip=1" %%a in (%1) do echo %%a
parse the contents of the line. Try FOR /f "skip=1 tokens=1-5" %%a in (%1) do echo %%b %%d
check the fourth item. Try
for /f "skip=1 tokens=1-5" %%a in (%1) do (
if /i .%%e.==.'DCF_t'. (
echo %%a 99.9 %%c %%d %%e
) else (
echo %%a %%b %%c %%d %%e
)
)
and you almost done, or at least in your way to the solution. See HELP FOR and HELP IF for more information.
This is a little bit cryptic for batch beginners. And there are many better languages to do this job.
But it can be done also with batch.
The key is to rewrite the file and modify the correct line.
set "otherValue=10"
setlocal EnableDelayedExpansion
(
For /f "tokens=1,2,*" %%a in (myFile.txt) do (
set "var=%%c"
if "!var!"=="!var:DCF_t=!" (
rem ** not found, echo the line
echo(%%a %%b !var!
) ELSE (
rem ** Found the line
echo(%%a %otherValue% !var!
)
)
) > outfile.txt
This assumes, that there are no exclamation marks in the text and that the lines are formatted always into three parts delimited by spaces or tabs.

Resources