Reading specific word from xml - batch-file

I have the following batch script to read an xml file and find a word (in this case, "factory"):
#echo off & setlocal enabledelayedexpansion
for /f "delims=" %%a in ('findstr /C:"factory" xcsconfig.xml') do set content=%%a
set content=%content:*"=%
set content=%content:~0,-1%
echo %content%
exit /b
Here's part of the xml file:
<loggers>
<recorder1>
<add name="factory" value="xlog"/>
<add name="alias" value="WSEnterprise.log"/>
</recorder1>
<recorder2>
<add name="factory" value="weblog"/>
</recorder2>
</loggers>
The code works fine and will always return the "first" founding - value="weblog"/. My question is, is there a way to return the founding under a specific tab? (i.e. I want to search specific under recorder1 instead of record2 tab, and return answer value="xlog"/). Thanks in advance.
EDIT: I changed my expected answer, it was incorrect

#ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sectionstart=recorder1"
SET "insection="
for /f "delims=" %%a in ('type q25062317.txt') do (
IF DEFINED insection (
ECHO "%%a"|FINDSTR /c:"factory" >NUL
IF NOT errorlevel 1 SET "content=%%a"
)
ECHO "%%a"|FINDSTR /i /L /c:"<%sectionstart%>" > NUL
IF NOT ERRORLEVEL 1 SET insection=Y
ECHO "%%a"|FINDSTR /i /L /c:"</%sectionstart%>" > NUL
IF NOT ERRORLEVEL 1 SET "insection="
)
set content=!content:*"=!
set content=!content:*"=!
set content=!content:~1,-1!
echo %content%
GOTO :EOF
I used a file named q25062317.txt containing your data for my testing.

You can incorporate also the next statements inside the do block of the for cycle. I mean:
setlocal EnableDelayedExpansion for /f "delims=" %%a in ('findstr /C:"factory" xcsconfig.xml') do (
set content=%%a
set content=!content:*"=!
set content=!content:~0,-1!
echo !content!
)
In this way the output is not only the last XML code line but all the code lines that contain the "factory" string in the file considered. Of course this example doesn't echo only a single desired string but this is possible setting a condition to the output of the loop.

Here is a robust tool that can help you - the command looks like this to get the line you need and it can be wrapped in a for /f loop.
type file.xml |findrepl "<recorder1>" /e:"</recorder1>" /b:"factory"
This uses a helper batch file called findrepl.bat (by aacini) - download from: https://www.dropbox.com/s/rfdldmcb6vwi9xc/findrepl.bat
Place findrepl.bat in the same folder as the batch file or on the path.

Related

Nested /F looping and If statements in batch file

I have two .txt files. One contains numbers, and the other one contains filepaths. I want to combine these two files to a .csv. The combination is based on wether the number (from nrs.txt) is in the string of the filepath (nodups.txt).
Now I have the following code for this:
#setlocal enableextensions enabledelayedexpansion
for /F %a IN (Output\nrs.txt) DO (
SET "nrs=%a"
for /F %b IN (Output\nodups.txt) DO (
SET "pathstring=%b"
SET csvdelim=,
IF NOT x!pathstring:%nrs%=""!==x%pathstring% %nrs%,%pathstring%>>new2017.txt
)
)
#endlocal
However, I keep having the following issues with the code:
The pathstring never seems to get set. (when I run the code without the if statement, The nrs variable gets set but the pathstring is set to %b). I've seen a lot of possible solutions on here already but none seem to work for me (setting variables like !var! and using usebackq).
The IF statement in the second for loop gets the following error message =""!==x%pathstring% was unexpected at this time. The ="" should remove the nr. from the path (if its there). When I replace "" with something else it still does not work.
The file contents are:
File nrs.txt:
12345
12245
16532
nodubs.txt:
C:\tmp\PDF_16532_20170405.pdf
C:\tmp\PDF_1234AB_20170405.pdf
C:\tmp\PDF_12345_20170506.pdf
Desired output:
12345, C:\tmp\PDF_12345_20170506.pdf
16532, C:\tmp\PDF_16532_20170405.pdf
I really hope someone can help me out with this !
This solution use a different approach, based on arrays:
#echo off
setlocal EnableDelayedExpansion
rem Load array from nodubs.txt file
pushd "Output"
for /F "tokens=1,2* delims=_" %%a in (nodubs.txt) do set "nodubs[%%b]=%%a_%%b_%%c"
rem Process nrs.txt file and show output
(for /F %%a in (nrs.txt) do (
if defined nodubs[%%a] echo %%a, !nodubs[%%a]!
)) > new2017.txt
In a batch file for variables need two percent signs.
There is no need to put %%A into a variable, use it directly.
#setlocal enableextensions enabledelayedexpansion
for /F %%a IN (Output\nrs.txt) DO (
findstr /i "_%%a_" Output\nodups.txt >NUL 2>&1 || >>new2017.txt Echo %%a
)
#endlocal
Instead of a second for, I'd use findstr to search for the entry of nrs.txt enclosed in underscores.
if no find use condiotonal execution on failure || to write to the new file.
According to changed preliminaries another answer.
#Echo on
Pushd Output
for /F "tokens=1-3 delims=_" %%A IN (
' findstr /G:nrs.txt nodubs.txt'
) DO >>"..\new2017.txt" Echo %%B, %%A_%%B_%%C
Popd
sample output:
> type ..\new2017.txt
16532, C:\tmp\PDF_16532_20170405.pdf
12345, C:\tmp\PDF_12345_20170506.pdf

Batch: search for files with certain extension, owner, fullpath and last write access and output in CSV

I'm trying to create a CSV with fullpath\filename, file owner and last write access (modification date) of all txt and html files from all hard drives of a data server.
Here's what I got so far:
set pgm=%~n0
set log=%~dpn0.log
set host=%COMPUTERNAME%
set csv=%host%.csv
set dir=D:\BME
if not exist "%csv%" type nul>"%csv%"
for /f "delims=;" %%a in ('dir /b/s %dir%\*.txt, %dir%\*.html') do (
>>%csv% echo "%%a"
)
That outputs the path + filename of all found txt and html files of a certain folder in a CSV. I tried this command to get the hard drives:
wmic logicaldisk where drivetype=3 get caption
But I can't get my head around how to store that in a variable or file and loop through it and also retrieve the owner and last modification date and put it into a new column of the csv file.
I can't get my head around how to store that in a variable
Use the following batch file.
GetDrives.cmd:
#echo off
setlocal enabledelayedexpansion
rem skip=1 to remove the header
rem findstr to remove blank lines
for /f "skip=1" %%d in ('wmic logicaldisk where drivetype^=3 get caption ^| findstr /r /v "^$"') do (
set _drive=%%d
echo !_drive!
)
endlocal
Notes:
Be careful when using drivetype=3 as I have a removable drive of type 3. In the below output C: is a fixed hard disk and F: is a removable external USB drive.
Replace echo !_drive! as appropriate with a modified version of your existing code.
Example Output:
F:\test>GetDrives
C:
F:
F:\test>
Further Reading
An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
enabledelayedexpansion - Delayed Expansion will cause variables to be expanded at execution time rather than at parse time.
for /f - Loop command against the results of another command.
wmic - Windows Management Instrumentation Command.
DavidPostill answered how-to store wmic logicaldisk … output in a variable;
to retrieve file last modification date: use echo "%%a","%%~ta" in your script using %~t Parameter Extension;
to retrieve file owner: echo "%%a","%%~ta","!_owner!" where _owner variable comes from getRealOwner subroutine based on modified schletti2000's answer Get ownership information from command line by using wmic.
The script:
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "pgm=%~n0"
set "log=%~dpn0.log"
set "host=%COMPUTERNAME%"
set "csv=%host%.csv"
set "dir=D:\BME"
set "dirmask=%dir%\*.txt, %dir%\*.html"
rem if not exist "%csv%" type nul>"%csv%"
>"%csv%" (
for /f "delims=;" %%a in ('dir /b/s %dirmask% 2^>NUL') do (
set "_fFullPath=%%~a"
set "_fLastWrite=%%~ta"
set "_fOwner="
call :getRealOwner
SETLOCAL EnableDelayedExpansion
echo "!_fFullPath!","!_fOwner!","!_fLastWrite!"
ENDLOCAL
)
)
)
type "%csv%"
goto :continue
:getRealOwner
SET "ESCAPED=%_fFullPath:\=\\%"
SET "UNDELIMITED="
for /F "skip=2 delims=" %%g in ('
wmic path Win32_LogicalFileSecuritySetting where Path^="%ESCAPED%" ^
ASSOC /RESULTROLE:Owner /ASSOCCLASS:Win32_LogicalFileOwner ^
/RESULTCLASS:Win32_SID 2^>NUL
') do (
SET "UNDELIMITED=%%g"
call :process_wmioutput
)
if NOT defined UNDELIMITED set "_fOwner=???"
exit /B
:process_wmioutput
SET "DELIMITED=%UNDELIMITED: =•%"
FOR /F "delims=• tokens=10,12" %%G in ("%DELIMITED%") DO set "_fOwner=%%H\%%G"
exit /B
:continue
I used next settings to demonstrate various output:
set "dir=D:"
set "dirmask=%dir%\loc*.vbs %dir%\bcd*.log %dir%\act*.xsl %dir%\diag*.xml %dir%\chec*.csv"
Output - non-privileged cmd window:
==> D:\bat\SO\39034430.bat
"D:\odds and ends\tempx\links\testDJ\LocUsers.vbs","mypc\user","25.12.2014 00:13"
"D:\tempWin\ActivityLog.xsl","NT AUTHORITY\SYSTEM","24.02.2016 13:12"
"D:\tempWin\CompatTelemetryLogs\diagerr.xml","???","12.08.2015 03:17"
"D:\tempWin\CompatTelemetryLogs\diagwrn.xml","???","12.08.2015 03:17"
"D:\test\check_acl.csv","BUILTIN\Administrators","06.03.2016 14:28"
Output - privileged (run as administrator) cmd window:
=ADMIN=> D:\bat\SO\39034430.bat
"D:\odds and ends\tempx\links\testDJ\LocUsers.vbs","mypc\user","25.12.2014 00:13"
"D:\tempWin\ActivityLog.xsl","NT AUTHORITY\SYSTEM","24.02.2016 13:12"
"D:\tempWin\CompatTelemetryLogs\diagerr.xml","NT AUTHORITY\SYSTEM","12.08.2015 03:17"
"D:\tempWin\CompatTelemetryLogs\diagwrn.xml","NT AUTHORITY\SYSTEM","12.08.2015 03:17"
"D:\test\check_acl.csv","BUILTIN\Administrators","06.03.2016 14:28"

Replace field value in property file using batch

Can anyone help me to replace a field value in property file using batch.
I have this field in my application.properties file: accessKey=AKIAJ2Q and I want to replace it with accessKey=XXXXX
I tried with sed command as recommanded here but it didn't work. The send command is not recognized by windows 10.
I tried also the following code:
SET key="XXXXX"
FOR /F %i IN (application.properties) DO SET accessKey=%key%
pause
Any help would be appreciated.
Thanks
There is surely a way to replace a string inside a txt/properties file using pure batch.
Taking above example to replace accessKey in application.properties
file.
#ECHO OFF
SETLOCAL
SET "sourcedir=C:\<Add directory path of application.properties>"
(
FOR /f "usebackqdelims=" %%a IN ("%sourcedir%\application.properties") DO (
FOR /f "tokens=1*delims==" %%g IN ("%%a") DO (
IF /i "%%g"=="accessKey" (
ECHO(%%g=xxxx
) ELSE (
ECHO(%%a)
)
)
)>application_new.properties
:: This new file now contains a modified version.
rem ECHO(MOVE /y application_new.properties "%sourcedir%\application.properties"
GOTO :EOF
There is no way to "replace" something inside a text file with pure batch. You could use a 3rd party tool like Find'n'Replace or even some PowerShell commands. But what you can do is to "copy" the text file into a temp file while replacing the token you are looking for. Afterwards you can delete the original file and replace it with the temporary one. Here is the code:
#echo off
setlocal enabledelayedexpansion
set sourcefile=something.txt
set tempfile=tempfile.txt
set oldtoken=AKIAJ2Q
set newtoken=XXXXX
type nul>%tempfile%
for /f "tokens=*" %%l in (%sourcefile%) do (
set line=%%l
set line=!line:%oldtoken%=%newtoken%!
echo !line!>>tempfile.txt
)
del %sourcefile%
move %tempfile% %sourcefile%

Batch file to create multiple variables from single lines in a text file

I have a text file with the names of computer names and corresponding static i.p. addresses in the following format.
COMPUTER NAME:PC ADDRESS=154.100.1.1 MASK=255.255.254.0
COMPUTER NAME:PC2 ADDRESS=100.100.1.1 MASK=255.255.254.0
I would like to take the values from each line and put them as variables in a batch file for use later. Is this possible? The overall goal is to have the values from this easily edited text file to be used in netsh commands in another batch file.
I've looked around and found ways to take lines of a text file and place them in one variable using the snippet below. However, I do not know how to create multiple variables from one line. If someone could help me with this I'd greatly appreciate it!
#echo o
setlocal enabledelayedexpansion
set Counter=1
for /f %%x in (D:\COMP_T.txt) do (
set "comp!Counter!=%%x"
set /a Counter+=1
)
This should work:
#echo off
setlocal EnableDelayedExpansion
set "Count=1"
for /f "tokens=1,2,3,4,5,6,7 delims==: " %%A in (C:\File.txt) do (
set "%%A[!Count!]=%%C"
set "%%D[!Count!]=%%E"
set "%%F[!Count!]=%%G"
set /a "Count+=1"
)
:: Call other batch script here.
endlocal
Example Output:
COMPUTER[1]=PC
COMPUTER[2]=PC2
ADDRESS[1]=154.100.1.1
ADDRESS[2]=100.100.1.1
MASK[1]=255.255.254.0
MASK[2]=255.255.254.0
Here is a solution that avoids the need for delayed expansion. It uses FINDSTR to insert a line number followed by : at the beginning of each line. The search string of "^" is guaranteed to match every line in the file.
The only other issue is to set TOKENS and DELIMS to parse the line properly.
#echo off
setlocal
for /f "tokens=1,4,6,8 delims=:= " %%A in ('findstr /n "^" "d:\comp_t.txt"') do (
set "comp%%A=%%B"
set "addr%%A=%%C"
set "mask%%A=%%D"
set "counter=%%A"
)
To use the set of variables in another batch file, line by line, just parse the lines as done in other answers here, and call the other batch file with the metavariables.
#echo off
for /f "tokens=1,2,3,4,5,6,7 delims==: " %%a in ('type "File.txt" ') do (
echo "computer_name=%%c"
echo "address=%%e"
echo "mask=%%g"
Call "batch script" "%%c" "%%e" "%%g"
)

How do I exclude specific file names from an MS DOS dir list?

I am creating an MS DOS batch script that needs to list every .bat file in the current directory, but not show autoexec.bat or other utilities or systems .bat files that shouldn't be run by the user.
I currently have DIR "*.bat" /B /P
This lists all .bat files appropriately, but it shows autoexec.bat. How would I exclude that from the list? Also slightly important, how could I chop off the file extensions and show more than the 7-characters DOS limits files to?
Constraints: I am not able to use a DOS version above WinME. That is the version I am using.
Thanks for any help.
EDIT:
There is plenty of information on the internet about doing this, but it is all in the windows command processor, not MS DOS. Please understand that DOS and the Command Prompt are not the same thing.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
echo %%~Na
)
)
EDIT: Some explanations added
Batch file processing is slow, so you should use techniques that allows a Batch file to run faster. For example:
Try to use the minimum lines/commands to achieve a certain result. Try to avoid external commands (*.exe files) like find, findstr, fc, etc. specially if they work on small amounts of data; use if command instead.
Use for %%a in (*.bat)... instead of for /F %%a in ('dir /B *.bat').... The second method requires to execute cmd.exe and store its output in a file before for command can process its lines.
Avoid pipes and use redirections instead. A pipe require the execution of two copies of cmd.exe to process the command at each side of the pipe.
A simple way to check if a variable contain a given string is trying to delete the string from the variable: if the result is different then the string exists in the variable: if "!variable:%string%=!" neq "%variable%" echo The string is in the variable.
Previous method may also be used to check if a variable have anyone of a list of values: set list=one two three, if "!list:%variable%=!" neq "%list%" echo The variable have one value from the list. If the values of the list may have spaces, they must be separated by another delimiter.
EDIT: New version added as answer to new comments
The easiest way to pause one page at a time is to use more filter this way:
theBatchFile | more
However, the program must reorder the output in order to show it in columns. The new version below achieve both things, so it does not require more filter; you just need to set the desired number of columns and rows per page.
#echo off
setlocal EnableDelayedExpansion
rem Add more names separated with slashes here:
set exclude=/autoexec/
rem Set the first two next variables as desired:
set /A columns=5, rows=41, wide=(80-columns)/columns, col=0, row=0
rem Create filling spaces to align columns
set spaces=
for /L %%a in (1,1,%wide%) do set spaces= !spaces!
set line=
for %%a in (*.bat) do (
if "!exclude:/%%~Na/=!" equ "%exclude%" (
rem If this column is less than the limit...
set /A col+=1
if !col! lss %columns% (
rem ... add it to current line
set name=%%~Na%spaces%
set "line=!line!!name:~0,%wide%! "
) else (
rem ... show current line and reset it
set name=%%~Na
echo !line!!name:~0,%wide%!
set line=
set /a col=0, row+=1
rem If this row is equal to the limit...
if !row! equ %rows% (
rem ...do a pause and reset row
pause
set row=0
)
)
)
)
rem Show last line, if any
if defined line echo %line%
Antonio
attrib +h autoexec.bat
should hide autoexec.bat and it should thus not appear in the list
DIR "*.bat" /B /P | find /v "autoexec" | for %i in (*.bat) do #echo %~ni
Using for to process each file name individually:
setlocal enabledelayedexpansion
for /f %%i in ('dir "*.bat" /b') do (
set system=0
if "%%i"=="autoexec.bat" set system=1
if "%%i"=="somesystem.bat" set system=1
if !system!==0 echo %%i
)
Another method without variables:
for /f %%i in ('dir "*.bat" /b') do call :test %%i
goto continue
:test
if "%1"=="autoexec.bat" goto :eof
if "%1"=="somesystem.bat" goto :eof
echo %1
goto :eof
:continue
For both, you can add new filenames to exclude from the list.

Resources