Batch: Don't parse comment of key-value - parsing

I am using the following code to parse an config.ini-file:
#setlocal enableextensions enabledelayedexpansion
#echo off
set file=%~1
set area=[%~2]
set key=%~3
set currarea=
for /f "usebackq delims=" %%a in ("!file!") do (
set ln=%%a
if "x!ln:~0,1!"=="x[" (
set currarea=!ln!
) else (
for /f "tokens=1,2 delims==" %%b in ("!ln!") do (
set currkey=%%b
set currval=%%c
if "x!area!"=="x!currarea!" if "x!key!"=="x!currkey!" (
echo !currval!
)
)
)
)
endlocal
It works fine as long as there are no comments in the same line as they keys and values.
For example:
[BACKUP]
HOST=128.110.111.11 ;Comment is included in !currval!
PORT=5901
USER=user1
Unfortunately I can't find a way to exclude everything after the last character of the string "128.110.111.11"..
Any help is appreciated. Thanks!

The best batch has to offer towards achieving the goal is a combination of for loops to process the string. There is no innate command that can achieve this in a single step.
In a way though, you can make a command to complete the necessary set of commands by a assigning them to a variable as a macro
For example, in the below script the macro completes the necessary steps for this goal by:
Delimitng the Variables content using ;
Iterating over the length of the string from end to start - The example assumes a maximum string length of 250 characters; an arbitrary number for the point of the example.
Remove only trailing spaces using If condition logic and substring modification
Stop further modification of the variables content by using a true/false switch to flag that the last digit of the string contains a non-space character
Note : Substring modification is used at the point of the the macros expansion to supply the name of the variable to be processed.
#Echo off & Setlocal enableDelayedexpansion
Set "RemTrail=Set "end=0"&(For /F "Tokens=1 Delims=;" %%G in ("^^!$v^^!")Do Set "$V=%%G")&For /L %%i in (250,-1,0)Do (if "^^!$V:~%%i,1^^!"==" " (If not "^^!End^^!"=="1" Set "$V=^^!$V:~0,%%i^^!")Else (If not "^^!$V:~%%i,1^^!"=="" Set "End=1"))"
rem // usage example
Set "string=trail of spaces ; comment string "
Set "string2=uncommented string with trailing spaces and poison chars < & " " | * > "
Echo/[!string!]
Echo/[!string2!]
%RemTrail:$V=String%
%RemTrail:$V=String2%
Echo/[!string!]
Echo/[!string2!]
A slighty modified version that Allows the Delimiter to be modified at expansion, at the expense of returning the modified result in a fixed return variable ($V) instead of the original variable name:
#Echo off & Setlocal enableDelayedexpansion
Set "RemTrail=For %%n in (1 2)Do if %%n==2 (Set "end=0"&(For /F "Tokens=1 Delims=DLM" %%G in ("^^!$V^^!")Do Set "$V=%%~G")&For /L %%i in (250,-1,0)Do (if "^^!$V:~%%i,1^^!"==" " (If not "^^!End^^!"=="1" Set "$V=^^!$V:~0,%%i^^!")Else (If not "^^!$V:~%%i,1^^!"=="" Set "End=1")))Else Set $V="
rem // usage example
Set "string=trail of spaces ; comment string "
Set "string2=uncommented string with trailing spaces + poison chars < & | * " " > "
Echo/[!string!]
Echo/[!string2!]
%RemTrail:DLM=;%"!string!"
Echo/[!$V!]
%RemTrail:DLM=;%"!string2!"
Echo/[!$V!]
%RemTrail:DLM=+%"!string2!"
Echo/+ Delim example&Echo/[!$V!]

Solution 1:
for /f "usebackq delims=;" %%a in ("!file!") do (
Including the semicolon as a delimiter ensures only that part of the line up to, but not including the semicolon is assigned to token 1 which is assigned by default to the metavariable %%a
Disadvantage : the spaces between the end of the string and the semicolon are retained in %%a and hence currval and will be echoed.
Solution 2 :
for /f "tokens=1,2 delims== " %%b in ("!ln!") do (
Inclusion of the space as an extra delimiter will assign the value between the first delimiter found (=) and the second ([space]) to %%c.
Disadvantage : The value displayed as %%c will be truncated at the space
Solution 3:
Use solution 1 and then change
set currval=%%c
to
CALL :setcurrval %%c
AND then endlocal becomes
endlocal
goto :eof
:setcurrval
SET "currval=%*"
goto :eof
which terminates the local environment and exits the batch.
CALLing the internal subroutine :setcurrval assigns the value of the remainder of the line to currval, except for the terminal spaces, hence producing %%c minus any terminal spaces.
Note that the colons are significant.

Related

Windows batch script parse string inside single quotes separated by commas

input.txt:
['Chinese Simplified', 'Traditional Chinese HK', 'Traditional Chinese TW', 'English', 'French', 'German', 'Indonesian', 'Italian', 'Korean', 'Malay', 'Portuguese', 'Portuguese Brasil', 'Russian', 'Spanish', 'Spanish Latin', 'Tagalog']
Desired output:
Chinese Simplified
Traditional Chinese HK
Traditional Chinese TW
English
French
ETC.
I tried something like this:
for /f "tokens=3" %%A in ('findstr /c:, "input.txt"') do echo %%A >> output.txt
#ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q36607414.txt"
FOR /f "usebackqdelims=[]" %%a IN ("%filename1%") DO (
SET "line=%%a"
SET "line=!line:'="!"
FOR %%b IN (!line!) DO ECHO(%%~b
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q36607414.txt containing your data for my testing.
Read each line,assigning the first token delimited by brackets to %%a
Transfer to line for string-manipulation
Replace ' with " using delayedexpansion to access run-time value of line
Use simple for to regurgitate resultant list of quoted items separated by spaces and commas; the ~ removes the quotes.

Batch output parsing

I have the following command and output:
fastboot get
< waiting for device >
...
(bootloader) ---------------------------------------------------------
(bootloader) Device-ID
(bootloader) 2FC9A68923FD175AA6E13657181CA6AB
(bootloader) 4AE438F12376AFA85D0E3467AE83A752
(bootloader) ---------------------------------------------------------
OKAY [ 0.020s]
finished. total time: 0.020s
How can I get the serial as: 2FC9A68923FD175AA6E13657181CA6AB4AE438F12376AFA85D0E3467AE83A752
also please explain the solution as much as possible
#echo off
setlocal enabledelayedexpansion
:: Get the line containing the string "Device-ID"
:: Use findstr to show the line number, then take everything left of the colon
:: This assumes that the script is in the same directory as your output data and the data is in data.txt
for /F "tokens=1 delims=:" %%A in ('findstr /C:"Device-ID" /N data.txt') do set id_line=%%A
:: For the first id_line lines of data.txt, store that value in a dummy variable
:: Store the line after that in id_part[1], and the line after that in id_part[2]
(
for /L %%A in (1,1,!id_line!) do (
set /p skip_line=
)
set /p id_part[1]=
set /p id_part[2]=
)<data.txt
:: For if_part[1] and then id_part[2],
:: Split the value of the variable on the space between (bootloader) and the value
:: Store the right side of the value in the id_part variable
for /L %%A in (1,1,2) do (
for /F "tokens=2" %%B in ("!id_part[%%A]!") do set id_part[%%A]=%%B
)
:: Join the two parts of the ID together
set serial=!id_part[1]!!id_part[2]!
:: Display the ID
echo !serial!
pause

Windows Batch: How to set the output of one command as a variable and use it in another command?

I'm trying to parse a variable. Say NAMELIST = "AAA BBB CCC" and store each one as a variable. Then, these new variables must be used in another command. Eg:
perl.exe C:\action.pl <VAR1>
perl.exe C:\action.pl <VAR2>
perl.exe C:\action.pl <VAR3>
I'm new to Windows Batch so any help would be appreciated.
I am aware of this thread but don't fully understand the solution
Windows batch files: How to set a variable with the result of a command?
When you refer to "store each one in a variable", the involved concept here is array. You may split the words of NAMELIST variable into 3 array elements this way:
setlocal EnableDelayedExpansion
set i=0
for %%a in (%namelist%) do (
set /A i=i+1
set VAR!i!=%%a
)
This way, you may use each array element directly:
perl.exe C:\action.pl %VAR1%
perl.exe C:\action.pl %VAR2%
perl.exe C:\action.pl %VAR3%
Or, in a simpler way using a loop:
for /L %%i in (1,1,3) do perl.exe C:\action.pl !VAR%%i!
EDIT: You may use this method with an unlimited number of values in the NAMELIST variable, just use the previous value of %i% instead the 3 (better yet, change it by "n"). I also suggest you to use the standard array notation this way: VAR[%%i]:
setlocal EnableDelayedExpansion
set namelist=AAA BBB CCC DDD EEE FFF
set n=0
for %%a in (%namelist%) do (
set /A n+=1
set VAR[!n!]=%%a
)
for /L %%i in (1,1,%n%) do perl.exe C:\action.pl !VAR[%%i]!
Variables in batch can be set by using for loop. I'll try to explain the example given in the link.
for /f "delims=" %%a in (command) do #set theValue=%%a
Here For /F is used to break up the output into tokens. "delims=" means no explicit separator is given so "space" is assumed. %%a is like index variable of loop however instead of traditional index variable in programming languages where index variable has a numeric value index variables in batch can store the tokens i.e. output of command. set command then sets the variable "theValue" to %%a which holds the output/token of the command.
Thus if the statement is:
for /f "delims=" %%a in (`echo Hi everyone!`) do #set theValue=%%a
theValue will then hold "Hi" as it is the first token seprated by space.
You can specify your own separator as per your requirement. Hope this helps!

Need help writing a batch file to read a MS Access .ldb lock file with null delimiters

I am trying to create a batch file to read a Microsoft Access .ldb lock file. The lock file contains a list of computer names and user names. I want to extract the computer names and eventually run them against an external command.
The format of the batch file is a single row with
(1) a computer name
(2) a NULL character (Hex 00)
(3) approximately 20 spaces
(4) the user name
(5) a NULL character
(6) approximately 20 spaces
repeating.
Example in Notepad++ with (NUL) representing Hex 00:
COMPUTER0123(NUL) Admin(NUL) COMPUTER0507(NUL) Admin(NUL)
I've tried several methods using FOR to read the file but can't get past the first computer name.
setlocal EnableDelayedExpansion
set file=database.ldb
for /F %%a in ('type %file%') do (
echo %%a
)
For for most of my Access databases, the user name in the file is Admin. I've been able to use FIND to tell me how many occurrences of "Admin" are in the file (plus 1).
for /f "delims=" %%n in ('find /c /v "Admin" %file%') do set "len=%%n"
set "len=!len:*:=!"
echo %len% (minus 1) computer names to process
<%file% (
for /l %%l in (1 1 !len!) do (
set "line="
set /p "line="
echo(!line!)
)
)
Iterating through the found lines doesn't work, probably because there only is one line in the file (no carriage returns).
I would like to find a solution that would work with a standard install of Windows XP.
After receiving an accepted answer, I combined that into a batch file that I'm posting below. I named the file ShowUsersInLDB.bat and put it in my SendTo folder.
#echo off
::===================================================================
:: Put this in your SendTo folder and it will let you right-click
:: on an Access .ldb/.laccdb lock file and tell you the computer
:: names that have opened the database.
::
:: After the computer names are shown, this will prompt you to
:: search for the user names associated with each computer. This
:: depends upon finding a 3rd party file named NetUsers.exe in
:: the user profile folder. Feel free to change the path if you
:: want to store the file in another location.
::
:: NetUsers.exe can be downloaded from here: http://www.optimumx.com/downloads.html#NetUsers
::
:: Notes:
:: 1) Keep in mind that sometimes after people leave the database
:: the lock file still shows their computer name. Don't jump
:: to conclusions.
:: 2) NetUsers.exe seems to report all users who have logged on
:: to the computer and not logged off, including services.
:: If you aren't familiar with your user names or your users are
:: sharing remote desktops/Citrix/Terminal Services, you may have
:: to guess who might have created the lock entry.
::
:: Installation:
:: You may find a batch file named Install_UsersInLDB.bat that will
:: copy this file to the SendTo folder and the NetUsers.exe file to
:: the user profile (or a place you define).
::
:: Ben Sacherich - March 2014
:: Please let me know if you have any ideas for improvements.
::===================================================================
setlocal
set file="%1"
:: Make sure the file has a compatible extension.
if "%~x1"==".ldb" goto :ExtensionIsValid
if "%~x1"==".laccdb" goto :ExtensionIsValid
echo.
echo "%~n1%~x1" is not the correct file type.
echo.
pause
goto :End
:ExtensionIsValid
echo The Access "%~n1%~x1" file contains
echo the following computer names:
echo.
set "compNameLine=1"
for /f %%A in ('more "%file%"') do (
if defined compNameLine (
echo %%A
set "compNameLine="
) else set "compNameLine=1"
)
echo.
echo Are you ready to look up the user names on each computer?
pause
set "compNameLine=1"
for /f %%A in ('more "%file%"') do (
if defined compNameLine (
::echo %%A
"%userprofile%\netusers" \\%%A
set "compNameLine="
) else set "compNameLine=1"
)
echo.
echo -- Validation finished at %time%
pause
:End
exit
CMD.EXE generally does not play nicely with NUL bytes. But there are a few external commands that can handle NUL bytes.
You also have to worry about the length of the "line". CMD.EXE does not like lines longer than 8191 bytes long.
I think your best bet is MORE since it converts NULs into new lines.
The following should echo your computer names.
#echo off
setlocal
set "file=database.ldb"
set "compNameLine=1"
for /f %%A in ('more "%file%"') do (
if defined compNameLine (
echo %%A
set "compNameLine="
) else set "compNameLine=1"
)

Extracting certain characters from the last line of text file using a .bat file

What I'm trying to accomplish here is to pull data from the last line of this file ftp://ftp.nhc.noaa.gov/atcf/tcweb/invest_al902012.invest. I've managed to download it and save it as a script.txt file through a .bat file. I now want to extract the latitude(13.5N) and longitude(27.2W) as well as pressure(1009) from the last line of the file and write it to a new file.I then used this code to do part of what I want:
#echo off
setlocal EnableDelayedExpansion
for /f "delims=" %%x in (script.txt) do (
set "previous=!last!"
set "last=%%x"
)
echo !previous!>> "test3.txt"
for /f "delims=*" %%x in (test3.txt) do (
set line=%%x
set chars=!line:~35,-125!
echo !chars!>> "test.txt"
)
I'm illiterate when it comes to batch coding. This is probably extremely inefficient and only extracts the latitude part of the code I want. The file will always contain the same amount of characters in the last line so I'm thinking I'm just not grasping the concept of the !line part of the code. Any help is greatly appreciated.
The file is comma delimited, so it is probably easier to let FOR /F parse the line into tokens and keep just the ones you want.
This really simple solution parses and sets values for each line, but only the last line is remembered. The performance should be fine as long as the file never becomes huge.
#echo off
for /f "tokens=7,8,10 delims=," %%A in (script.txt) do (
set lat=%%A
set long=%%B
set pres=%%C
)
echo latitude=%lat%, longitude=%long%, pressure=%pres%
If you want to strip off the spaces, then you could simply use search and replace.
echo latitude=%lat: =%, longitude=%long: =%, pressure=%pres: =%
I do not simply include space as a delimiter in the FOR /F statement because that can throw off the token counting when a value is sometimes blank and sometimes not.

Resources