Searching for semicolon inside a string in batch causes weird issues - batch-file

I am trying to write a simple batch command that reads the second line of a file (ProfileName), looks for a ";" in that line and then splits the line and stores it in two variables (ProfileName and RRSProfileName)
for /F "tokens=1 skip=1" %%A in (%ContentFilePath%) do ( SET ProfileName=%%A )
ECHO %ProfileName% | findstr /spin ";">nul
IF %ERRORLEVEL%==0 (
FOR /F "tokens=1,2 delims=;" %%A in ("%ProfileName%") do ( SET ProfileName=%%A& SET RRSProfileName=%%B )
)
ContentFile contains 2 lines
blah
blah1
For some reason, ProfileName variable does not get set if the "IF" statement is present. If I remove the "IF" statement, ProfileName gets set to blah1. This is bizzare. Can someone help? Both ProfileName and RRSProfileName are set to "" initially.

for /F "tokens=1,2 skip=1delims=;" %%A in (q22602116.txt) do SET "ProfileName=%%A"&SET "RRSProfileName=%%B"
worked perfectly well for me, assuming that Profilename should be set to the portion before the semicolon on the last line and RRSprofilename to the portion after (if it exists)
But - be careful of the presence of Spaces in a string-assignment - they are significant (original batch appeared to have trailing spaces...) - the quotes positioned just so should overcome this characteristic...

findstr /spin
it search in subdirectories (/s) omitting non printable files (/p) ignoring case (/i) numbering output lines (/n), and you are not giving any file, so findstr fails as its arguments are not correct. From here you get errorlevel 1, so, the code inside the if is not executed
Better use
for /F "usebackq tokens=1 skip=1" %%A in ("%ContentFilePath%") do ( SET "ProfileName=%%A" )
ECHO %ProfileName%| find ";" > nul
IF %ERRORLEVEL%==0 (
FOR /F "tokens=1,2 delims=;" %%A in ("%ProfileName%") do ( SET "ProfileName=%%A" & SET "RRSProfileName=%%B" )
)
Or just (if it is possible, i don't know all your cases), join the two steps into one
for /f "usebackq tokens=1,2 skip=1 delims=;" %%a in ("%ContentFilePath%"
) do ( set "ProfileName=%%a" & set "RRSProfileName=%%b" )
It reads the same required line, if semicolon is present, it is used to split the line and each of the variables retrieve the required content.

Related

Batch: Find substring with quotes in string

I cannot get this to work. I am reading an XML file line by line and then look at each line if it contains a specific tag <assemblyIdentity name="PostDeploymentAction" version". When I find it, I would modify it and write everything back into a file.
However, I can not find the tag since it contains quote marks.
#ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion
....some more code....
SET dllFile=%DestPath%\%ProjectName%.dll.manifest
IF NOT EXIST "%dllFile%" (
ECHO File %ProjectName%.dll.manifest does not exist^^!
GOTO ERROR
) ELSE (
ECHO Modifying %ProjectName%.dll.manifest in directory:
ECHO %DestPath%
REM Create a temporary file in the folder, where this batch file is being executed from
>"temp.xml" (
FOR /F "usebackq delims=" %%I IN ("%dllFile%") DO (
SET "line=%%I"
REM Insert existing line before modification
SETLOCAL DisableDelayedExpansion
ECHO %%I
ENDLOCAL
REM Find correct version number
SET "myVariable=<assemblyIdentity name="PostDeploymentAction" version"
IF not "!line!"=="!line:myVariable=!" (
echo !line!
)
....some more code....
)
)
)
Whatever escape characters I use, it will not find this particular line (or it finds every line). Everything else in above code works fine - only IF not "!line!"=="!line:myVariable=!" does not. Any help much appreciated.
Thanks
Use another method to compare the strings:
#echo off
setlocal enabledelayedexpansion
; set "myvariable=<assemblyIdentity name="PostDeploymentAction" version"
set myvariable
for /f "delims=" %%a in (test.txt) do (
echo "%%a"|findstr /c:"!myvariable:"=\"!">nul && (
echo DEBUG: found %%a
REM do something special here
) || (
echo %%a
REM write line unchanged
)
)
(you have to escape the doublequotes with findstr; findstr` uses the backslash as escape character)
In the end, I ended up with
SET "xmlTag=<assemblyIdentity name="PostDeploymentAction"
FOR /F "usebackq delims=" %%A IN ("%dllFile%") DO (
ECHO "%%A"|FINDSTR /c:"!xmlTag:"=\"!">nul && (
FOR /F "tokens=2,3 delims=^=" %%B IN ("%%A") DO (
SET version=%%C
SET version=!version:~0,-9!
ECHO Found PostDeploymentAction.dll version number !version!
)
)
)
This gives me the version number I was after. The full XML line is <assemblyIdentity name="PostDeploymentAction" version="1.1.0.0" language="neutral" processorArchitecture="msil" />. The first FOR loop gets the entire line out of the XML file, while the second FOR gets the actual version number "1.1.0.0".
The second FOR is a bit weird, but it works. However, I am sure there are better ways...
BTW, the above was a bit slow since FINDSTR is called for each line of the file (read file line by line and then analyze each line with FINDSTR).
There is a much, much faster version by calling FINDSTR only once for the entire file and then analyzing the return result found by FINDSTR.
SET "xmlTag=<assemblyIdentity name="PostDeploymentAction"
FOR /F "tokens=*" %%A in ('FINDSTR /c:^"!xmlTag:"=\"!^" ^"%dllFile%^"') DO (
FOR /F "tokens=5 delims=^=^ " %%B IN ("%%A") DO (
SET version=%%B
ECHO Found PostDeploymentAction.dll version number !version:~1,-1!
)
)

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"
)

Using Wildcard in Set command in batch file

ok I am trying to strip the first two characters from a file I am using this script.
#echo off
Set "InputFile=C:\New Folder\test.txt"
Set "OutputFile=C:\New Folder\New\test.txt"
setLocal EnableDelayedExpansion > "%OutputFile%"
for /f "usebackq tokens=* delims= " %%a in ("%InputFile%") do (
set s=%%a
>> "%OutputFile%" echo.!s:~2!
)
which works perfect if I use the correct name. What I need to do is use a wild characters since the name of the file is different each time. When trying this it does not work.
#echo off
Set "InputFile=C:\New Folder\H*.txt"
Set "OutputFile=C:\New Folder\New\H*.txt"
setLocal EnableDelayedExpansion > "%OutputFile%"
for /f "usebackq tokens=* delims= " %%a in ("%InputFile%") do (
set s=%%a
>> "%OutputFile%" echo.!s:~2!
)
from
I'd like to use a wildcard with the SET command in Windows Batch so I don't have to know exactly what is in the string in order to match it
The asterisk IS a wildcard and WILL match multiple characters, but
will ONLY match everything from the very beginning of the string. Not
in the middle, and not from the end.
Useful Searches:
*x
*how are you? The above two searches CAN be matched. The first will match everything up to and including the first "x " it runs across.
The second one will match everything up to and including the first
"how are you?" it finds.
Legal, but Unuseful, searches:
x* Hello* OneThree The above three searches can NEVER be matched.
Oddly they are also legal, and will cause no errors. One exception:
Hello and x* WILL match themselves, but only if they are the very
beginning of the string. (Thanks Jeb!)
the surrounding for-loop does the wildcard processing (giving full qualified filenames)
#echo off
for /f %%i in ('dir /b C:\New Folder\H*.*') do (
echo processing %%i
Set "InputFile=C:\New Folder\%%i"
Set "OutputFile=C:\New Folder\New\%%i"
setLocal EnableDelayedExpansion > "%OutputFile%"
for /f "usebackq tokens=* delims= " %%a in ("%InputFile%") do (
set s=%%a
>> "%OutputFile%" echo.!s:~2!
)
endlocal
)
Note: if you have more than one line in those files, it will remove the first two characters from each line*.

Batch to parse lines containing a specific string from an input 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

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.

Resources