Use "for" loop inside a new window using "START" - batch-file

I need to search through a file and get some result but using a new window.
If I run the "for" loop with out the START command am getting the correct results, but when I open the process in a new windows the results are wrong.
Start "" /Min Cmd.exe /C For /f "tokens=1,2,3" %%a in (file.txt) do (
set value1=%%a
set value2=%%b
)
echo. %value1%
echo. %value2%
This is what am getting as a result:
%a
%b

I'm not sure what you expect.
Possibility 1) - You want the ECHO statements to run in your parent batch script, displaying the result of the FOR /F command that was run in another window.
This simply cannot be done. You cannot execute a FOR command in one window, and process the iterations (the DO portion) in another window.
Also, if you manage to run the entire FOR loop in another window, any variables you set will be totally separate from your parent batch environment. Your parent batch script will not have access to the variables from the other window.
Possibility 2) - You want everything (including the ECHO statements) to run within the new Window.
This is possible, but awkward, and can also be problematic depending on the file content.
You must put the entire "script" as a single line that gets passed as a parameter to the CMD /C command. Quoting and escaping can quickly become tricky. The entire line will be parsed in a single pass, so you would need the child window to use delayed expansion. But FOR loops will corrupt content if delayed expansion is enabled and the content includes !. You cannot toggle delayed expansion ON and OFF within the loop because the new window has a command line context, not batch, so the SETLOCAL ENABLEDELAYEDEXPANSION command does not work.
I don't see what possible purpose this serves, but the following will run, with the constraint that values containing ! will be corrupted. I had to add a PAUSE command so that you have an opportunity to see the output.
start "" /min cmd.exe /v:on /c "(for /f "tokens=1,2" %%a in (file.txt) do #set "value1=%%a"&set "value2=%%b")&echo(!value1!&echo(!value2!&pause"

When you use a FOR loop in a bat file you need to double the %%. From the command line (which is your case... since you are starting a new instance of CMD.exe) only use single %. Change both occurrences of %%a to %a and %%b to %b and it will work.

Related

How to copy un-sanitized string to clipboard with batch script

I want to put a user inputted string which contains an ampersand into the clipboard using batch. I can modify the string, and I can get it to print to the terminal using setlocal EnableExtensions EnableDelayedExpansion
but I can't pipe it to the clipboard.
There is an in depth discussion here which talks about why pipes can break things, but I couldn't understand it well enough to get around my problem.
https://www.robvanderwoude.com/battech_inputvalidation_setp.php
setlocal EnableExtensions EnableDelayedExpansion
set /P "INPUT=Paste the stuff in the terminal please"
set "SEARCHTEXT=+"
set REPLACETEXT=%%2B
for /F "delims=" %%A in ("%INPUT%") do (
set "string=%%A"
set "modified=!string:%SEARCHTEXT%=%REPLACETEXT%!"
echo !modified! | clip
)
Because the string I'm trying to modify contains "&username" in it, the output I get is:
'username' is not recognized as an internal or external command,
operable program or batch file.
If I only echo !modified!, there are no errors. How can I get an arbitrary un-sanitized string into the clipboard?
The major problem in your code is the following line:
echo !modified! | clip
A pipe (|) creates a new cmd instance for either side. You have got delayed expansion enabled in your script, so the variable !modified! becomes expanded when the whole command line is parsed, then the pipe is executed, and then the new cmd instance for the left side receives the variable already expanded, including all potential poisonous characters, like &, for example.
To prevent !modified! to be expanded immediately, we need to escape the exclamation marks like ^^! (^^ becomes first escaped to a single ^, so ^! is left during the delayed expansion phase), which lets the ! be treated as a literal character and no variable expansion happens at first.
The new cmd instance (for the left side of the pipe in our situation) now has got delayed expansion disabled, so we need to explicitly instantiate another (nested) one with delayed expansion enabled (by cmd /V):
cmd /V /C echo(^^!modified^^!| clip
With this technique we force the variable !modified! to be expanded as late as possible, hence by the inner-most cmd instance, which avoids the expanded string to be received by any other instance, and therefore, poinsonous characters become hidden from the parser.
In addition, I used the safe echo variant echo(..., because echo ... might fail under certain circumstances (imagine ... is the literal string /?). Moreover, I removed the SPACE in front of |, because such would become echoed as well, unintentionally.

can't seem to run multiple commands in a loop in a windows batch file

ECHO OFF
setlocal enabledelayedexpansion
CD C:\Work\
FOR /D /r %%G in ("t*") DO (
START C:\prg.exe %%G\input_1 %%G\input_2 %%G\cpp_output
FOR /D /r %%H in (%%G\cpp_output\*.txt) DO (
FOR /F %%i in ("%%H") DO (
#set FN=%%~nxi DO (
START C:\Work\compareResults.m %%G\matlab_output\FN.txt %%G\cpp_output\FN.txt
)
)
)
)
PAUSE
I have been trying to get this .bat code to run but it doesn't work - a window opens and closes quickly - i.e prg is not run. However, when I run:
ECHO OFF
setlocal enabledelayedexpansion
CD C:\Work\
FOR /D /r %%G in ("t*") DO (
START C:\prg.exe %%G\input_1 %%G\input_2 %%G\cpp_output
)
PAUSE
prg is run. I guess there seems to be a problem with the extra commands but I just don't know what the problem is.
According to http://ss64.com/nt/for.html one can have a few commands in a single for and they can be in different lines. However that didn't work so I tried using & to have multiple commands and I've also tried using the caret (^) for breaking lines. None of these seem to work and I can't even really debug anything since the batch window disappears too fast. Any ideas for what I am doing wrong? Or even how to debug the .bat program?
...
#set FN=%%~nxi DO(
START C:\Work\compareResults.m %%G\matlab_output\FN.txt %%G\cpp_output\FN.txt))))
This won't work. This is bad syntax. DO can't stand behind a SET command. In your case DO goes only with FOR:
FOR something DO (
codeline 1
codeline 2
...
codeline n
)
If you want several command lines to be executed within a FOR block you just have to write them between the brackets (), each command in a new line.
However, there is also a way to combine several commands in only one line (don't use it here): command1&command2&...comandn will execute commands 1 to n one after the other. They will be executed even if one of the commands throws an error. If you use && instead (command1&&command2&&...comandn), each command will only be executed if the previous command was proceeded without errors.

Opening a list of processes with cmd parameters from a file

I have a script which will write a file (currently C:\test.txt) of processes (it checks for processes from a pre-defined list).
I then run some other code (not important what gets done here, but part of this is to end these processes).
My problem is, at this point in my script, I need to be able to relaunch the processes that were terminated but load them with the cmd parameters they were runnign with previously.
The test.txt file will look something like this:
"C:\folder1\folder2\application1.exe" param1
"C:\folder1\folder2\folder3\application2.exe" param1 param2
"C:\folder4\application3.exe"
"C:\folder1\folder2\folder3\application4.exe" param1 param2 param3 param4
etc..
I used a for loop to take the lines from the file and try to run them;
for /f "usebackq tokens=1,* delims= " %%C in (C:\test.txt) do (
%%C %%D
)
This woks fine, except that the script waits for the first process to complete (i.e. terminate again), before loading the next one, and these processes will not end!
I tried to use
start %%C %%D
but I loads a new CMD window with the file path, then tries to run the file with the name from %D
Using;
start %%C %%C %%D
does seem to work, but I've no idea why, and I'm sure that its not the right way to do this.
Can anyone explain why this works, and the others do not, and if there is a proper way to do this??
Thanks
The first parameter after start command within quotes is considered as 'Window Title'. Then followed by command and the parameters.
Thats why
start %%C %%D
does not work as %%C which is within quotes is considered window title and tries to run %%D command.
This should also work:
start "" %%C %%D
See:
start /?
Why can't I start programs in the command line without /d? (Windows 7x64)

set fileName and echo to cmd.exe in for loop of batch?

I'd like to put each of the many properties' file names into variable fileName and echo them out to the command prompt window. But only the last properties file name to be cycled thru is printed out as many times as there are properties files. Is there an easy fix to this problem. I know that ...DO echo %%-nxG can do the same thing but I'd like to save the file name in %%~nxG for future use.
FOR %%G IN (C:\ExecutionSDKTest_10.2.2\*.properties) DO (
set fileName=%%~nxG
echo %fileName%
)
You need to use delayed expansion:
setlocal enabledelayedexpansion
FOR %%G IN (C:\ExecutionSDKTest_10.2.2\*.properties) DO (
set fileName=%%~nxG
echo !fileName!
)
Environment variables in cmd are expanded when a command is parsed – in this case this includes the whole block in parentheses. So %fileName% gets replaced by an empty string because it didn't have a value before the loop ran. Delayed expansion uses ! instead of % and changes variable evaluation so that they are evaluated just before a command is run.
help set has more details about why and when it is necessary. In general, whenever you modify and use a variable within a loop you have to use delayed expansion, but it comes with a few other benefits too.

Batch File: Multiple Commands on one line with Set

I have a framework where I can only run stuff through PowerShell, but I need to run batch file commands. I'm trying to run a PowerShell Script, something like:
cmd /c blah
for blah I want to do something like:
set myPath = c:\theDir && if not exist %myPath% mkdir %myPath%
This will not work the first time I run it as the set command doesn't seem to take affect until the second line. Any ideas?
This is because cmd evaluates variables when a line is parsed, not when it's run. To get the latter behaviour you'll have to use delayed expansion:
cmd /c /v:on "set MyPath=C:\theDir&& if not exist "!myPath!" mkdir "!myPath!"
Note also that you must not have spaces around the = in a set, otherwise you're creating a variable name with a space at the end (which is to say, your approach would never have worked anyway).
for %d in (some\path and\maybe\another\one) do #if not exist "%d" md "%d"
You can also define the delayed expansion before you run multiple commands. That way you would not have to open a new CMD instance:
Setlocal EnableDelayedExpansion
set say=Hello && echo !say! && echo Done!
You can also do like this
SET _KillElevated=1& SET _KillWithGrace=1

Resources