Windows Batch: Call function for each path in delimited string - batch-file

I have a variable that contains the following:
"pdfList=D:\BundleManager\AssetPackageManager.unity;D:\BundleManager\AssetPackageManager.unity\.vs\AssetPackageManager.unity;D:\Crafting\CraftingExample.unity;D:\ResMan\FFResManExample.Unity;"
And I want to call a function for each of those paths separated by ; The code I currently have is
for /F "delims=;" %%a in ("%pdfList%") do (#echo %%a)
But this is just echoing the following
D:\BundleManager\AssetPackageManager.unity
I've tried setting tokens=* as an option but this just echos the value of pdfList complete with ; still present. Where am I going wrong?

The problem with your code is that for /F loops line-by-line, rather than token-by-token. A better solution is to use for without any switches. for will tokenize data, splitting on unquoted spaces, commas, semicolons, and tabs.
To prevent pathnames containing spaces or commas from being truncated, you can massage the data and replace all semicolons with ";" using batch variable substring substitution, then surround the whole thing in quotation marks. See this page for full details on substring replacements.
So basically,
a;b c;d e;f
becomes
a";"b c";"d e";"f
becomes
"a";"b c";"d e";"f"
which is easily tokenized, and spaces are preserved. Apply this principle to your code above:
#echo off & setlocal
set "pdfList=D:\BundleManager\AssetPackageManager.unity;D:\BundleManager\AssetPackageManager.unity\.vs\AssetPackageManager.unity;D:\Crafting\CraftingExample.unity;D:\ResMan\FFResManExample.Unity"
for %%a in ("%pdfList:;=";"%") do echo(%%~a
The output is now:
D:\BundleManager\AssetPackageManager.unity
D:\BundleManager\AssetPackageManager.unity.vs\AssetPackageManager.unity
D:\Crafting\CraftingExample.unity
D:\ResMan\FFResManExample.Unity

Related

Using batch echo to write a vbe file (characters are not escaped)

So I'm currently writing a tutorial about security and for that reason I have to write a vbe file (encoded script written in VBScript) using a batch file.
So, I just have to write this to a file:
##~^mgAAAA==6 P3MDKDP"+k;:PH+XY~###&fks~D;EdO{6k^+SPhnk/Co8WX~~AMkYnm6ks+B~T+O|wmYtBPDn:a{2lDtS~6kxms{alY4~###&s+k/Con8K6~',h/T4GavJKndDJ~~8BPEwlDlV,2M.WMJbP###&2zEAAA==^#~#
(Note: There are some characters that cannot be printed above).
But the problem is that I never managed to write it successfully, I tried escaping all the characters using instructions from http://www.robvanderwoude.com/escapechars.php and it didn't work.
I tried using DelayedExpansion like this:
SET "foo=##~^mgAAAA==6 P3MDKDP"+k;:PH+XY~###^&fks~D;EdO{6k^+SPhnk/Co8WX~~AMkYnm6ks+B~T+O|wmYtBPDn:a{2lDtS~6kxms{alY4~###&s+k/Con8K6~',h/T4GavJKndDJ~~8BPEwlDlV,2M.WMJbP###^&2zEAAA==^#~# "
setlocal EnableDelayedExpansion
(
echo !foo!
) > test.vbe
And it did not work either, I have problems with characters that are not escaped.
Any ideas?? Thanks!!
The reason is obvious, that is a quotation mark after [...P3MDKDP]. Since you assign the variable "foo" to jumble characters with a open and a close quotation mark, like so SET "foo=...", batch think you stop assigning "foo" after [...P3MDKDP]. This leaves [+k;:PH+XY~.....] alone, without assigning to a variable or working with commands. Batch can't recognize it, and so the command prompt quit automatically.
What you can do is, assign the part after the quotation mark to another variable, I named it "foo2" in the following example:
#echo off
setlocal enabledelayedexpansion
SET "foo=##~^mgAAAA==6 P3MDKDP""
SET "foo2=+k;:PH+XY~###^&fks~D;EdO{6k^+SPhnk/Co8WX~~AMkYnm6ks+B~T+O|wmYtBPDn:a{2lDtS~6kxms{alY4~###&s+k/Con8K6~',h/T4GavJKndDJ~~8BPEwlDlV,2M.WMJbP###^&2zEAAA==^#~# "
echo !foo!!foo2!>test.vbe
pause >nul
And also, if you add another quotation mark before / after the quotation mark, like so [P3MDKDP ""], even though you did not assign the second part to a new variable, it still work, but it output an extra quotation mark in the string.
maybe this little trick helps you:
#echo off
for /f "delims=[]" %%n in ('find /n "REM DATA:" "%~dpnx0"') do set /a n=%%n
more +%n% "%~dpnx0">test.vbe
REM rest or your batchfile
goto :eof
REM DATA:
##~^mgAAAA==6 P3MDKDP"+k;:PH+XY~###^&fks~D;EdO{6k^+SPhnk/Co8WX~~AMkYnm6ks+B~T+O|wmYtBPDn:a{2lDtS~6kxms{alY4~###&s+k/Con8K6~',h/T4GavJKndDJ~~8BPEwlDlV,2M.WMJbP###^&2zEAAA==^#~#
(this trick avoids any character escaping or splitting the string. Can also be used to write a multiline text)

batch file changing double quote

Having trouble running a batch file.
SET startIN="D:\Documents and Settings\%USERNAME%\Desktop\DataXfer Helper\StartFolder"
SET collection="D:\Documents and Settings\%USERNAME%\Desktop\DataXfer Helper\StartFolder\*.zip"
FOR /F %%G IN (‘dir /b %collection%\*.zip’) DO “C:\Program Files\Winzip\wzunzip” –E %startIN%\%%G %startIN%
When I type the line at the command prompt - it works fine (the only difference is when typed at the command prompt I use %G instead of %%G).
So, the environement variables are being created properly - but when I run the batch, the single quotes and the hyphen before the E are being turned into other characters (can't identify what they are).
So, any ideas why running the batch would change the characters?
Thank you.
There are a couple of problems:
The symbols in your FOR line are not supported ASCII chars. Retype the ', ", and - in the command line to correct them.
The string expansion is going to include the quotes you set in the path above. For example, %startIN%\%%G will expand to "D:\Documents and Settings\%USERNAME%\Desktop\DataXfer Helper\StartFolder"\MyFile.zip. When dealing with paths, make sure your logic is aware of quotes so they don't get trapped in the middle of the result.
Try updating your script to this:
REM Remove the quotes from the path.
REM Quotes will be added once we know the full path.
SET startIN=D:\Documents and Settings\%USERNAME%\Desktop\DataXfer Helper\StartFolder
REM Quote here because we know the full path.
SET collection="%startIN%\*.zip"
REM Update FOR loop to include parsing options and properly quote output.
REM Also update invalid ASCII chars.
FOR /F "usebackq tokens=* delims=" %%G IN (`dir /b %collection%`) DO "C:\Program Files\Winzip\wzunzip" -E "%startIN%\%%G" "%startIN%"

I cannot seem to get this string to loop through in batch, and I only can get a single line of output.

My code so far:
for /F "tokens=*" %%A in (#opm.txt) do set str=%%A
set str=%str:~0,3%
#echo.%str% > #tags.txt
Basically, I have a huge list of things that I am attempting to take the first three letters from, however, I only end up getting one of those things from the list right now. For example:
The word 'eagle' is on the list. The end result should be EAG (and preferably in caps).
Any tips?
If you want to do more than one statement in a for loop you need to use brackets:
for /F "tokens=*" %%A in (#opm.txt) do (
set str=%%A
set str=%str:~0,3%
#echo.%str% > #tags.txt
)
Note that opening bracket is in the same line as for ... do ... statement. In this case, you need to use delayed expansion to manipulate variables inside a loop (that makes variables enclosed with exclamation marks to be resolved in place):
#setlocal ENABLEDELAYEDEXPANSION
for /F "tokens=*" %%A in (#opm.txt) do (
set str=%%A
set str=!str:~0,3!
#echo.!str! >> #tags.txt
)
#endlocal
Please also note that redirection syntax was changed from > to >>. Single bracket redirection overwrites #tags.txt every times statement is executed. Double bracket redirection appends lines at the end of the file (you may want to assure that the file is empty before the loop).
Replacing capitalization of a letters in batch is fairly complicated without external tools. This is not a text-processing-friendly technology. Have you considered Python instead?

Using inputs from a batch file to create a new, saved as a different name batch file

I am trying to create a batch file to input 3 pieces of data and use that data to create another batch file. Just create it, and stop. The batch maps several network drives for users that haaven't a clue as to how to do it.
I have a "master.bat" and using notepad I am using "replace" to fill in the "username" "Password" and "drive path". I thought I would try to get it down to entering the variables into the "master.bat" creating a "custom.bat" for that user.
I got a lot of help here getting to the final step. Everything is working except the final part. Now that I have all the variables as well as a template to put them in, how do I get that first batch file to create the cuctomized output as a workable file that I can send the user where all they do is run it.
One way would be to use your template in file form and replace placeholders in there by your actual values:
setlocal enabledelayedexpansion
for /f %%L in (template.cmd) (
set "Line=%%L"
set "Line=!Line:[username]=!username!"
...
>network-drives.cmd echo !Line!
)
This assumes placeholders like [username] in the template and corresponding variables defined.
However, I always get a little anxious if I use data read from a file in a batch. When I recently had to create a batch file from another I went the following route:
(
echo #echo off
echo net use !drivepath! \\server\share "/user:!username!" "!password!"
echo net use !drivepath2! \\server\share2 "/user:!username!" "!password!"
) > network_drives.cmd
Care has to be taken with things like closing parentheses and several characters reserved for the syntax you may need in the generated batch file. But this approach is entirely self-contained, albeit a little harder to maintain.
It is simple to embed the template within your batch file. There are multiple ways to do this. One is to simply prefix each template line with :::. I chose that sequence because : is already used as a batch label and :: is frequently used as a batch comment.
Delayed expansion can be used to do your search and replace automatically!
There are just 3 special characters you need to worry about if you want to include them in your output. These special characters are probably not needed for the original question. But it is good to know how to handle them in a general sense.
An exclamation literal ! must be either escaped or substituted
A caret literal ^ can be escaped or substituted if it appears on a line with an exclamation. But it must not be escaped if there is not an exclamation on the line. Caret substitution is always safe.
Use substitution to start a line with :
#echo off
setlocal
::The following would be set by your existing script code
set drivePath=x:
set username=rumpelstiltskin
set password=gold
::This is only needed if you want to include ! literals using substitution
set "X=!"
::This is only needed if you want to include ^ literal on same line
::containing ! literal
set "C=^"
::This is only needed if you want to start a line with :
set ":=:"
::This is all that is needed to write your output
setlocal enableDelayedExpansion
>mapDrive.bat (
for /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"') do #echo(%%A
)
::----------- Here begins the template -----------
:::#echo off
:::net use !drivePath! \\server\share "/user:!username!" "!password!"
:::!:!: Use substitution to start a line with a :
:::!:!: The following blank line will be preserved
:::
:::echo Exclamation literal must be escaped ^! or substituted !X!
:::echo Caret with exclamation must be escaped ^^ or substituted !C!
:::echo Caret ^ without exclamation must not be escaped

Find line in text file, check for text in between?

Question about Batch/Windows/CMD:
I would like that my batch file can search for a line (which I already achieved, but what comes next not), it looks like this:
<name>MyName</name>
It needs to find the text in between <name> and </name>. After that it needs to set that as a variable (%name%).
Does anyone have any idea?
EDIT: if someone wants to give an answer, please list the code. Perl is OK, but this should be open-source and not everyone has Perl.
It can be done this way (assuming your input is in file "test1.html"):
findstr "<name>" test1.html > temp1.lis
FOR /F "tokens=2 delims=>" %%i in (temp1.lis) do #echo %%i > temp2.lis
FOR /F "tokens=1 delims=<" %%i in (temp2.lis) do #echo %%i > temp3.lis
The first line is a guard that only HTML/XML tag
"name" will match in the two FOR lines (you may
already have done this). The result is saved in a temporary
file, "temp1.lis".
The second line capture what is to the right of the first
">" - in effect what is after "<name>". At this stage
"MyName</name" is left in temporary file "temp2.lis" (as
the closing tag also contains ">"). Note the double "%"s
(%%i) as this is in a BAT file (if you want to test directly
from the command line then it should only be one "%").
The third line capture what is to the left of the first "<"
- this is the desired result: "MyName" (is left of "<" in
"MyName</name"). The result is in variable %%i and you
can call a function with %%i as a parameter and access the
result in that function (in the FOR line above the function
was the built-in "echo" and the result thus ended up in
temporary file "temp3.lis" by the redirection of standard
output)
Note that the above only works if
<name>MyName</name>
is the first HTML/XML tag in a line.
If that is not the case or you want a more robust solution
you can instead call a function in the first FOR line (that
receives %%i as the first parameter). That function can then
replace "<name>" with a single character that you are
sure is not in the input, e.g.:
set RLINE=%MYLINE:<name>=£%
Explanation: if the input line is in variable %MYLINE% then
"<name>" will be replaced with "£" and the result will be
assigned to variable %RLINE%.
The reason for the replace is that the delimiters for the
FOR loop are single character only.
You can then use "£" as a delimiter in the FOR loop (to extract what is
to the right of "<name>" - as before):
echo %RLINE%>temp5.lis
FOR /F "tokens=2 delims=£" %%i in (temp5.lis) do #echo %%i > temp6.lis
You have to repeat this technique for "</name>"
(but only if <name>MyName</name> is not
the first HTML/XML tag in a line).
So as you see it is possible, but is quite painful.
Learn Perl, it's made for exactly that kind of thing.

Resources