Nested /F looping and If statements in batch file - 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

Related

In a Windows 10 batch file, is there a way to extract only the last total files count?

From a dir command that displays a number of sub-folders within a main folder, I am trying to extract the total number of files only. I am trying to use the FIND command with the string "File(s)", however this lists all of the file totals for each of the sub-folders, in addition to the overall total on the last line. I would like to limit my extraction to only this overall total, and none of the sub-folder file counts.
Whilst I've provided a simple one liner already in the comment section, it does not technically provide a method of doing what you wanted. The task you've explained is really to retrieve a substring of the last but one line of output from the DIR command with its /S option. This method prevents the need to use the FIND command to search for the language dependent string File(s) too.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "MainFolder=C:\Users\CoastalGuy\Documents"
Set "CommandLine=Dir "%MainFolder%" /S /A:-D"
Set "Last="
Set "LastButOne="
For /F Delims^=^ EOL^= %%G In (
'%CommandLine% 2^>NUL'
) Do (
If Defined Last (
SetLocal EnableDelayedExpansion
For /F "Tokens=1 Delims= " %%H In ("!Last!") Do (
EndLocal
Set "LastButOne=%%H"
)
)
Set "Last=%%G"
)
If Defined LastButOne (
Echo %LastButOne%
Pause
)
For the specific task you've posted, this script is a little over the top, but I've tried to create it more like a template, so that you could more easily adapt it for similar tasks, (by changing the variable values on lines 4 and 5, and modifying the Tokens and Delims values in the inner For /F loop as required).
Found this simple result on an internet search:
After doing a dir /s of the main folder and then exporting a file (Files.txt) of each of the file results using FIND "File(s)", the following command extracts just the last line of that file, which has the grand total of Files from all sub-folders.....
For /F "UseBackQ Delims==" %%A In ("Files.txt") Do Set "lastline=%%A"
Echo - %lastline%
Works Great,
Thanks,

Batch-File: Find String inside String does not work

I have tried to use the answer mentioned from here: [Find Substring in String] (Batch file: Find if substring is in string (not in a file))
I try to adapt the solution mentiones in the commands, so that I have my SearchVal saved inside a variable so this can be changed during runtime.
Minimal example:
set searchVal="cde"
set str1="abcdef"
setlocal enabledelayedexpansion
if not "x!str1:%searchVal%=!"=="x%str1%" echo It contains my subs
endlocal
pause
In my opinion this little batch should display that the strings contains my subs, however nothing is shown and I do not know why as I directly make use of the solution that should be working.
EDIT
Thanks to the commands I found my mistake.
In my current situation I look at files inside a folder and save the filename inside an array while doing a for-loop:
for /f "tokens=1 delims=" %%G in ('pathToFolder\*.properties /b') do (
if not "%%~G:%searchVal%=!"=="%%~G" echo It contains my subs !ID_Properties!
set filename[!ID_Properties!]=%%~G
set /a ID_Properties+=1
)
... where ID_properties is just a counter and searchVal my string I am looking for. Does anyone know how I can use the %%G inside the loop in the correct way so the search works as before?
Your for-loop syntax is not correct it seems like a mixture between executing a dir command and looping through files. I'll stick with the dir command option and using usebackq.
#echo off
setlocal EnableDelayedExpansion
set searchVal=cde
set ID_Properties=0
for /f "usebackq tokens=1 delims=" %%G in (`dir pathToFolder\*.properties /b`) do (
set file=%%G
if not "!file:%searchVal%=!"=="!file!" (
echo It contains my subs !ID_Properties!
set filename[!ID_Properties!]=!file!
set /a ID_Properties+=1
)
)
Filling the array is only done if the file contains your searchVal; don't know if this was/is you intention.
a For loop might be a bit much, depending on what you plan to do with the output. findstr is maybe a shorter option:
findstr /im "cde" *.properties && echo - found || echo not found
and add /s if you require recursive search through subdirectories:
findstr /ims "cde" *.properties && echo - found || echo not found

Using "for /F" command to find specific text in xml file and use as variable in a batch file

I am trying to find the following version number in a app.config file.
The file is XML format.
Line 8 in the file (Adding line in again as the greater/less than symbols were stripped from the post initially)
add key="ReleaseVersion" value="5.2.0.2"
I been using various FOR /F commands, have been close a couple of times.
However I have not been able to extract the 5.2.0.2 value and use as a variable
so far in my script.
Additionally while I am looking for this value 5.2.0.2, going forward the version number will change so I am not looking for a exact match e.g. "5.2.0.2", I am looking to capture what is in the inverted commas e.g. value="", and then using this as a variable in my script.
Example of what I have tried so far...
FOR /f "tokens=3 delims=5." %%a IN ('TYPE appsettings.config ^| FIND "ReleaseVersion"') DO SET do set word3=%%a
FOR /F delims^=^"^ tokens^=2 %%G IN ('FINDSTR /L "ReleaseVersion" "appsettings.config"')
FOR /f "tokens=3 usebackq delims== " %%G in (`appsettings.config`) do #echo %~G
Have tried a number of techniques but as yet, nothing has been successful.
Can post more information as required however that essentially covers the issue.
Supposing the add key="ReleaseVersion" value="5.2.0.2" portion is in a single line and the related value parameter appears after the ReleaseVersion substring, the following could work for you:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem define constants:
set "SEARCH=ReleaseVersion"
set "KEYWORD=value"
rem get line of interest and assign it to `LINE`:
for /F "delims=" %%L in ('findstr /L "%SEARCH%" "app.config"') do (
set "LINE=%%L"
)
setlocal EnableDelayedExpansion
rem cut everything off up to the search string:
set "LINE=!LINE:*%SEARCH%=!"
rem cut everything off up to the keyword:
set "LINE=!LINE:*%KEYWORD%=!"
rem extract the version number:
for /F tokens^=1^ delims^=^"^=^/^<^>^ %%N in ("!LINE!") do (
set "VNUM=%%N"
)
rem transfer the version number over the `setlocal`/`endlocal` barrier:
endlocal & endlocal & set "VNUM=%VNUM%"
echo ReleaseVersion: %VNUM%
exit /B
The string portion of interest does not need to look exactly like shown above, but may contain more or less spaces (for example add key = "ReleaseVersion" value = "5.2.0.2"), or include the " or not (like add key=ReleaseVersion value=5.2.0.2). The only condition is that the attribute key needs to appear before the attribute value.
If the search line is precisely this one:
add key="ReleaseVersion" value="5.2.0.2"
... then this code should work:
#echo off
setlocal
for /F "tokens=3" %%a in ('findstr "ReleaseVersion" "appsettings.config"') do set %%a
set "value=%value:~1,-1%"
echo %value%
If the layout of the search line change (more blank spaces or other characters, less quotes, etc) then previous code should need an adjustment.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q34445384.txt"
FOR /f "tokens=3delims==" %%a IN (
'findstr /L /c:"add key=\"ReleaseVersion\" value=" "%filename1%"') DO SET "release=%%~a"
ECHO release=%release%
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q34445384.txt containing your data for my testing.
Simply find the target string using findstr and set the environment variable to the third token using delimiters of =, removing the quotes from the value with ~.
This assumes uniqueness of the target text and that the structure of the line is exactly as posted.
Assuming app.config is valid, well-formed XML, the best way to scrape the release version is to query it via XPath. You can invoke PowerShell for this.
#echo off
setlocal
set "psCommand=powershell "^
select-xml \"//add[#key^='ReleaseVersion']\" app.config ^| %%{ $_.node.value };^
""
for /f %%I in ('%psCommand%') do set "version=%%~I"
echo %version%
This will parse app.config for a node named "add" which has an attribute named "key" whose value is "ReleaseVersion", then will return that node's "value" attribute's value. for /f captures it to a batch variable.

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 to change an image tag url in multiple html files using batch script?

There are more than 10 html files with image tags. Every time we deploy our build onto test site we need to change the img source. for eg <img src=/live/Content/xyz.png />
to <img src=/test/Content/xyz.png />.
After looking around and reading for sometime, i have come up with the following batch script, however i cant figure out how do i go further from here :
for /r %%i in (*.html) do echo %%i
for %%f in (*.html) do (
FOR /F %%L IN (%%f) DO (
SET "line=%%L"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "x= <--------------------WHAT DO I SET HERE?
echo %x%
ENDLOCAL )) pause
This is my first batch script, could anyone please guide me in the right direction?
#ECHO OFF
SETLOCAL enabledelayedexpansion
for /r U:\ %%i in (*.html) do (
echo found %%i
SET outfile="%%~dpni.lmth"
(
SETLOCAL disabledelayedexpansion
FOR /F "usebackq delims=" %%L IN ("%%i") DO (
SET "line=%%L"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "line=!line:/live/=/test/!
echo !line!
ENDLOCAL
)
ENDLOCAL
)>!outfile!
)
pause
GOTO :EOF
How about this development?
Notes:
I've modified your FOR/R to ECHO the HTML file being processed and use %%i rather than switching to %%f. U: is my RAMDRIVE; you'd need to modify that to suit.
outfile is set to generate a filename which matches the HTML filename, but with a .lmth extension (can't update in-place) - it gets that from the ~dpn prefixing the i, which means the drive, path and name of the file %%i. It's quoted to take care of potential spaces in the filename or pathname.
The next logical statement is (for /f...[lines] )>!outfile! which sends any echoed text to a NEW file !outfile!. The enabledelayedexpansion in the second physical line of the batch makes !outfile! the RUN-TIME value - as it is changed within the FOR r outer loop.
Since the actual HTML filename in %%i may contain spaces, it needs to be quoted, hence the 'usebackq' clause in the FOR/F. The delims= clause ensures that the ENTIRE line from the file "%%i" is applied to %%L - not just the first token (well, actually, makes the entire line the first token).
The SET command substitutes the string "/test/" for any occurrence of "/live/" in the RUN-TIME value of the variable lineand assigns the result to line. The resultant value is then ECHOd - which is redirected to outfile
Note that in your original, you would be assigning x in the set x= but echo %x% would have reproduced x as it stood when the line was PARSED because batch substitutes the value of any variable for %var% as part of the parsing phase. Consequently, the line would have become simply ECHO (since x would likely be unassigned) and bizarrely would have reported the echo state (Echo is OFF)
A couple of gatchas here. First, % and some other characters are notoriously hard to process with batch, so be careful. Next, FOR/F will bypass empty lines. This can be overcome if required. Third, this will replace ANY occurrence of /live/ in any case with /test/
Good luck!
Edit to support exclamation marks: 20130711T0624Z
Added SETLOCAL enabledelayedexpansion line and ENDLOCAL just before )>!outfile! to match

Resources