remove quotes "" from string in batch file - windows

I use:
FOR /F "delims=" %%G IN ("%command%") DO SET command=%%~G
to remove "" quotes from variable %command%. If command = "Shutdown /s /t 00", after this line it will be: Shutdown /s /t 00. and it works.
But when command contains a string where are a equal sign (=), it remove also this caracter. Example:
before, command = "D:\temp\stinger --ADL --GO --Silent --ReportPath= D:\temp --ReportOnly --Delete --Program"
After, command= D:\temp\stinger --ADL --GO --Silent --ReportPath D:\temp --ReportOnly --Delete --Program
Look, the quotes "" are removed, but also the sign = .
So, how to remove the quotes "" without removing the equal character.
Thanks

Instead of your for loop through the command, you could just use string manipulation.
set command=%command:"=%
the values after command are "=<nul> so you're getting rid of quotation marks in the variable command. Just as an extra example, you could also do %command: =_% to replace all spaces in command with underscores.

The reason your command fails is because the quotes in the string and the quotes in the IN() clause cancel each other out, so the remainder of the content is not quoted. The FOR /F parser treats an unquoted = as a token delimiter that is converted into a space. You would also have problems with poison characters like &, |, etc.
The problem is avoided by using delayed expansion. The delay state is toggled on before the FOR loop, and off within the loop so that any ! within the command are preserved.
setlocal enableDelayedExpansion
for /f "delims=" %%A in ("!command!") do endlocal & set "command=%%~A"
The major advantage of this approach is that you get the correct result regardless whether the command starts out quoted or not.

Related

Batch for-loop paths with quotes are strings instead of file-sets

I'm having trouble getting a FOR loop to read a quoted path as a file-set. I have a script similar to this, designed to process every line of the files I drag and drop onto it:
#ECHO OFF
FOR %%F IN (%*) DO (
ECHO %%F
FOR /F "DELIMS=" %%A IN (%%F) DO (
ECHO %%A
)
)
PAUSE
The first ECHO shows the file path. If it contains a space, there will be double-quotes around the path. The second ECHO shows each line in the file, unless the file path had a space. Then instead of lines, it's just the path again, but without quotes.
This makes sense to me after reading Windows' FOR documentation, which shows if quotes are given, it's read as a string, not a file.
FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
FOR /F ["options"] %variable IN ("string") DO command [command-parameters]
But some paths have spaces and presumably need quotes. How can I force FOR to interpret those as files?
I tried passing %%~f to the second FOR loop to always strip quotes, but then FOR complained it could not find the file, because the path was cut off at the first space. That's when I added the DELIMS option, to stop reading spaces as delimiters, but there was no change.
Read the same documentation and look at the usebackq options.
usebackq - specifies that the new semantics are in force,
where a back quoted string is executed as a
command and a single quoted string is a
literal string command and allows the use of
double quotes to quote file names in
file-set.
A batch file can be called with multiple arguments which can be enclosed in " as required on an argument string like a file name contains a space or one of these characters &()[]{}^=;!'+,`~ (or literally to interpret <>| like in a password string), but can be also passed to the batch file without surrounding double quotes. That must be taken into account on processing the batch file arguments like file names by explicitly removing surrounding " from each argument string and reference the resulting file name string with always enclosing it in " to have finally every file name enclosed in double quotes.
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
FOR %%I IN (%*) DO (
ECHO "%%~I"
FOR /F usebackq^ delims^=^ eol^= %%J IN ("%%~I") DO ECHO(%%J
)
ENDLOCAL
PAUSE
The first two command lines define completely the required execution environment which is:
command echo mode turned off to prevent output of each command before execution,
command extensions enabled as required for this batch file for %* and FOR /F,
delayed variable expansion disabled to process correct all file names even those with an exclamation mark and all lines in the files even those with an exclamation mark.
The outer FOR loop assigns one argument string after the other to the loop variable I exactly as passed to the batch file on starting it which means without or with surrounding double quotes.
The first ECHO outputs the argument string being hopefully the file name of a text file always enclosed in double quotes independent on file name passed to the batch file without or with surrounding double quotes.
The inner FOR loop with option /F assigns each non-empty line to the loop variable J and runs one more ECHO to just output the non-empty line.
FOR /F interprets by default a string in double quotes as string to process. The usage of the option usebackq changes this behavior. A string in double quotes is now interpret as file name of a text file of which lines should be processed one after the other. The file name passed as argument string to the batch file is always enclosed in " because of using "%%~I" which references the argument string assigned to loop variable I with removal of surrounding " and explicitly enclose the resulting file name string in " by the code in the batch file.
FOR /F always ignores empty lines which means lines not containing any character other than the line termination characters carriage return and line-feed. A text file is also processed correct on lines are terminated just with a line-feed (UNIX format). A carriage return is only ignored by FOR on being in byte stream of the file before the line-feed. Otherwise the carriage return is not interpreted as line termination and becomes therefore part of the line to process further.
FOR /F splits up by default a line into substrings (tokens) using normal space and horizontal tab character as string delimiters whereby leading spaces/tabs are removed from each line. Then is checked if the first character of first substring starts with a semicolon being the default end of line character in which case the line is also ignored for further processing independent on option tokens= if that option is also used which is not the case here. Otherwise without usage of option tokens= only the first space/tab delimited string is assigned to the specified loop variable for further processing by the command(s) in the body of the FOR loop.
delims= turns off the line splitting behavior by the definition of an empty list of delimiters. eol= defines no character as end of line character. Both together results in processing all lines in file even blank lines containing only spaces/tabs with the exception of empty lines.
The only possible syntax to define the FOR /F options delims= and eol= together with no delimiter and no end of line character is the used syntax with not enclosing the three options in " as usual as the usage of "usebackq delims= eol=" would result in " being interpreted as end of line character. A normal space, an equal sign, a comma, a semicolon and an OEM encoded no-break space found by cmd.exe on a command line not within an argument string enclosed in " is interpreted as argument string separator. But usebackq delims= eol= should be interpreted by cmd.exe as one argument string to pass to its internal command FOR. The solution is to escape the two spaces and the two equal signs with ^ to get them interpreted as literal characters and not as argument string separators by cmd.exe.
The command ECHO with just spaces/tabs appended would output the current status of command echo mode instead of the spaces/tabs. ECHO(%%J is used instead of ECHO %%J to prevent an output of command echo mode status if the line assigned to loop variable J consists of only spaces/tabs. The opening round bracket is interpreted as argument string separator in this case between the command ECHO and the string to output which is the non-empty line read from the file.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
echo /?
endlocal /?
for /?
pause /?
setlocal /?
See also:
DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ for a full explanation for the usage of ECHO( in this special use case.
Issue 7: Usage of letters ADFNPSTXZadfnpstxz as loop variable in this answer for an explanation why the letters F and A are not used in the code above as loop variables although both could be used here too.

Get result of command with quoted arguments within single quote command evaluation in Windows batch

How do you pass quoted arguments to an executable in a single-quoted evaluation such as FOR /F "delims=" %%i IN ('"executable path" arg1 "arg2 which contains spaces"') do ...?
As per many of the answers here, I'm trying to use the output of a console app in a Windows batch script, using the single quotes to get the console to evaluate it.
However, I need to quote some of the arguments I want to pass to that executable, which also needs to be quoted, as the path contains spaces as well.
But when I do that, the quoting around the executable path breaks.
Here is the would-be line:
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^="!album!"') DO set "falbum=%%i"
(Both !PathToExe! and !album! contain spaces. It seems like I need to escape the equal signs here, hence the circumflexes. Delayed expansion is on)
The above results in "Outcome A": Quoting is broken for the exe path
'<Part of path to exe>' is not recognized as an internal or external command, operable program or batch file.
I've tried different combinations of different quote usages and escapings, but haven't found a way to make it work.
Here are some attempts and their results:
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^=!album!') DO set "falbum=%%i")
No quotes around !album! results in "Outcome B": As expected, only the first word gets passed along with string=, all the other words get scattered as individual arguments.
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^=^"!album!^"') DO set "falbum=%%i")
FOR /F "delims=" %%i IN ('^"!PathToExe!^" action^=sanitize string^=^"!album!^"') DO set "falbum=%%i")
Trying to escape the quotes for the string= argument or both exe path and string arg: Outcome A (still breaks the quoting for the exe path, gives:)
'<Part of path to exe>' is not recognized as an internal or external command, operable program or batch file.
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^=^'!album!^'') DO set "falbum=%%i")
Using escaped single quotes: Outcome B again
FOR /F "delims=" %%i IN ('"!PathToExe!" action^=sanitize string^='"!album!") DO set "falbum=%%i")
Ending the single quote before the string= value and simply having it in quotes after that seems to result in everything being taken as a single first argument (command/path):
The system cannot find the file '"<path to exe>" action=sanitize string='"<Album var with spaces and whatnot>".
It does not matter whether the quotes are part of the variables or literally typed in the IN ('...') line.
Simple testing:
You could test this behavior if you copied %SystemRoot%\System32\cmd.exe to a directory with spaces, e.g. C:\folder with spaces\ and pasted the following script there:
#echo off
setlocal EnableDelayedExpansion
set PathToExe="%~dp0cmd.exe"
REM Toggle the next line to compare between quoted path with spaces and path without quotes or spaces:
REM set PathToExe=cmd.exe
set string=%~dp0
FOR /F "delims=" %%i IN ('!PathToExe! /C CD C:\windows\system32 ^& dir !string!') DO set "fstring=%%i"
echo !fstring!
pause
This should illustrate the challenge of having two quoted sections in one statement.
If the !string! variable remains unquoted, you'll get "The system cannot find the file specified.".
If the quotes of the !PathToExe! variable break, you'll see something like "'C:\folder' is not recognized as an internal or external command, operable program or batch file.".
The for /F command, when used to capture and parse command output, actually uses cmd /C to execute that command, which handles quotation marks in a particular way. From its help (cmd /?):
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
This means that:
for /F "delims=" %%I in ('"executable path" arg1 "arg2 which contains spaces"') do (…)
actually tries to execute the command line:
cmd /C "executable path" arg1 "arg2 which contains spaces"
leading to:
executable path" arg1 "arg2 which contains spaces
which is obviously invalid syntax.
To overcome this issue provide an additional pair of quotes:
for /F "delims=" %%I in ('^""executable path" arg1 "arg2 which contains spaces"^"') do (…)
It is a good idea to escape these additional quotes (by ^"), so there is no need to alter any potential escape sequences.

Replace multiple characters in a string from the command line

Its possible replace a staring with another like this
set x=abc
echo %x:b=d%
The output will be
adc
But how do you replace multiple characters.
For example I want b=>d but als c=>e
It possible with a loop/for but the question is how to do it on 1 line so I can use it from the command line.
I tried these variants
echo %x:b=d,c=e%
echo %x:b=d;c=e%
echo %x:b=d|c=e%
I can't get the syntax right or it isn't supported?
The syntax supported only one replace per expansion.
The problem is, that mutliple percent expansions in one line or in a command block doesn't work, because the percent expansion will be expanded, before any command is executed.
Therefore this fails, it outputs "abc"
set "var=abc"
set "var=%var:a=1%" & set "var=%var:b=2%" & echo %var%
But you could use CALL to force a second expansion phase.
set "var=abc"
call set var=%^var:a=1% & call set var=%^var:b=2% & call echo %^var^%
%^var.. looks odd, but it's necessary on the command line, because on the command line you can't escape percent signs, but you can prevent the expansion in the first round by adding carets in the variable name.
But the solution has a drawback, it appends spaces at the variable.
You can see that by using call echo ---%^var%---
To prevent that, you should use the extended SET-syntax with quotes set "var=content"
call set ^"var=%^var:a=1%^" & call set ^"var=%^var:b=2%^" & call echo %^var^%
Now, there are carets in front of the quotes to allow the carets in %^var to disappear.
As you can see, the solution is pretty simple
Well, you can use a for loop and still have everything in a single line:
(for %I in ("b=d" "c=e") do #call set ^"x=%^x:%~I%^") & call echo/%^x%
The call command introduces a second parsing phase, which is necessary when you want to write and read a variable within the same block of code.
If you have got delayed variable expansion enabled (like when you started the command prompt by cmd /V), you could change the command line to this:
(for %I in ("b=d" "c=e") do #set "x=!x:%~I!") & echo/!x!
I realise you said from cmdline, but you also did have the batch-file tag, therefore I will post the batch file solution regarless.
We create a list of search=replace as a variable, you can have as many search/replaces as you like, then simply loop through the list and let it run the replace for each and echo final modified variable when done.
#echo off
set x=abc
set lst="a=z","b=d","c=e"
for %%i in (%lst%) do call set x=%%x:%%~i%%
echo(%x%
If you are on a supported Windows system, it will have the PowerShell interpreter.
SET "X=abc"
FOR /F %a IN ('powershell -NoLogo -NoProfile -Command "('%X%' -replace 'b','d') -replace 'c','e'"') DO (SET "Y=%a")
ECHO %Y%
If this is placed into a .bat file script, double the percent % character on the FOR loop variable. %a becomes %%a.
SET "X=abc"
FOR /F %%a IN ('powershell -NoLogo -NoProfile -Command ^
"('%X%' -replace 'b','d') -replace 'c','e'"') DO (SET "Y=%%a")
ECHO %Y%

including special char (&) from "for delims"-result in batch file

I have a script that reads thru file and sets variable as it finds it.
#echo off
Setlocal EnableDelayedExpansion
for /f "tokens=*" %%V in ('findstr /I /C:title= "%~1"') do set title=%%V
echo %title%
In the txt file there is "title=variable & speed".
And the script only returns:
title=variable
'SPEED' is not recognized as an internal or external command,
operable program or batch file.
As it should return whole line.
This is the part, I have not found the solution yet. It should change the "&" to "-", as in finally this script renames files.
First, don't enable delayed expansion because of not needed here. It can result in findstr does not find the file to open if the batch file is called with a file name without or with a path containing one or more exclamation marks.
Second, the FOR option "tokens=*" results in removing leading spaces/tabs from a line output by FINDSTR not starting with a semicolon and if there is something left assign the rest of the line to specified loop variable. This is okay if this behavior is wanted here. Otherwise it would be better to use "delims=" which defines an empty list of delimiters resulting in assigning the entire line not starting with a semicolon to the specified loop variable. Not double quoted argument string delims^=^ eol^= defines an empty list of delimiters and no end of line character to get assigned also a line starting with a semicolon to the loop variable. The two equal signs and the space character must be escaped with caret character ^ to be interpreted as literal characters and not as argument separators.
Third, an ampersand outside a double quoted argument string is interpreted as operator to unconditionally execute the command after & after executing the command before &. For details see Single line with multiple commands using Windows batch file. For that reason it is recommended to enclose the argument string of command SET in double quotes as explained in detail on answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line?
So I suggest using following code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LoadedTitle="
for /F "tokens=*" %%V in ('%SystemRoot%\System32\findstr.exe /I /C:"title=" "%~1" 2^>nul') do set "LoadedTitle=%%V"
if defined LoadedTitle (
setlocal EnableDelayedExpansion
echo !LoadedTitle!
endlocal
)
endlocal
Read this answer for details about the commands SETLOCAL and ENDLOCAL.
Please note that /C:"title=" is used instead of /C:title= on FINDSTR command line as otherwise FINDSTR would in this special case search just for title. The reason is that the command line within the round brackets is executed in a separate command process started by FOR with cmd.exe /C in background and the equal sign not enclosed in a double quoted string and not escaped with ^ would be removed by current command process because of being interpreted as separator. In a command prompt window it is possible to use the FINDSTR command line with /C:title= without double quotes, but not here on this FOR command line in batch file.
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded findstr command line with using a separate command process started in background.
Temporary enabling delayed expansion just for output of the line with loaded title string is required because of usage of only echo %LoadedTitle% would be modified before execution to echo title=variable & speed and the ampersand is again not interpreted as literal character to output by ECHO, but as operator to run speed after execution of echo title=variable .
I recommend to read
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
How to debug a batch file?
A batch file writer must always take into account what is finally executed by Windows command processor after parsing a command line one or more times as this can be different than what is written in batch file on using environment variable references with syntax %variable%.
I Found the correct "formula" to script
#echo off
setlocal EnableExtensions EnableDelayedExpansion
for /F "tokens=*" %%V in ('%SystemRoot%\System32\findstr.exe /I /C:"title=" "%~1"
2^>nul') do set "title=%%V"
set title=!title:^&=-!
echo "!title!"
endlocal
As it does now that what I wanted, it returns:
"title=variable - SPEED"
It is not as you suggested but it does the job.

How do you strip quotes out of an ECHO'ed string in a Windows batch file?

I have a Windows batch file I'm creating, but I have to ECHO a large complex string, so I'm having to put double quotes on either end. The problem is that the quotes are also being ECHOed to the file I'm writing it to. How do you ECHO a string like that and strip the quotes off?
UPDATE:
I've spent the last two days working on this and finally was able to kludge something together. Richard's answer worked to strip the quotes, but even when I put the ECHO in the subroutine and directly outputted the string, Windows still got hung up on the chars in the string. I'll accept Richard's answer since it answers the question asked.
I ended up using Greg's sed solution, but had to modify it because of sed/windows bugs/features (it didn't help that it came with no documentation). There are a few caveats to using sed in Windows: you have to use double quotes instead of single quotes, you can't escape the double quotes in the string directly, you have to endquote the string, escape using the ^ (so ^") then beqin quote for the next section. Also, someone pointed out that if you pipe input to sed, there's a bug with a pipe being in the string (I didn't get to verify this since in my final solution, I just found a way not to have all quotes in the middle of the string, and just removed all quotes, I never could get the endquote to be removed by itself.) Thanks for all the help.
The call command has this functionality built in. To quote the help for call:
Substitution of batch parameters (%n) has been enhanced. You can
now use the following optional syntax:
%~1 - expands %1 removing any surrounding quotes (")
Here is a primitive example:
#echo off
setlocal
set mystring="this is some quoted text"
echo mystring=%mystring%
call :dequote %mystring%
echo ret=%ret%
endlocal
goto :eof
:dequote
setlocal
rem The tilde in the next line is the really important bit.
set thestring=%~1
endlocal&set ret=%thestring%
goto :eof
Output:
C:\>dequote
mystring="this is some quoted text"
ret=this is some quoted text
I should credit the 'environment variable tunneling' technique (endlocal&set ret=%thestring%) to Tim Hill, 'Windows NT Shell Scripting'. This is the only book I have ever found that addresses batch files with any depth.
The following approach can be used to print a string without quotes:
echo|set /p="<h1>Hello</h1>"
pushing this string into file:
echo|set /p="<h1>Hello</h1>" > test.txt
pushing this string into file and appending a CR/LF:
echo|(set /p="<h1>Hello</h1>" & echo.) > test.txt`
To check:
type test.txt
You can use the %var:x=y% construction that replaces all x with y.
See this example what it can do:
set I="Text in quotes"
rem next line replaces " with blanks
set J=%I:"=%
echo original %I%
rem next line replaces the string 'in' with the string 'without'
echo stripped %J:in=without%
To remove all quotation marks from a set variable, you need Delayed Variable Expansion to securely expand the variable and process it. Expansion using percent signs (i.e. %VAR% and %1) are inherently unsafe (they are vulnerable to command injection; read this for details).
SETLOCAL EnableDelayedExpansion
SET VAR=A ^"quoted^" text.
REM This strips all quotes from VAR:
ECHO !VAR:^"=!
REM Really that's it.
To strip quotes from a text file or a command output, things will get complicated because with Delayed Expansion, string like !VAR! within the text document will get expanded (within the %%i expansion in FOR /F) when it shouldn't. (This is another vulnerability—information disclosure—that's not documented elsewhere.)
To safely parse the document, a switch between delayed-expansion-enabled and -disabled environment is needed.
REM Suppose we fetch the text from text.txt
SETLOCAL DisableDelayedExpansion
REM The FOR options here employs a trick to disable both "delims"
REM characters (i.e. field separators) and "eol" character (i.e. comment
REM character).
FOR /F delims^=^ eol^= %%L IN (text.txt) DO (
REM This expansion is safe because cmd.exe expands %%L after quotes
REM parsing as long as DelayedExpansion is Disabled. Even when %%L
REM can contain quotes, carets and exclamation marks.
SET "line=%%L"
CALL :strip_quotes
REM Print out the result. (We can't use !line! here without delayed
REM expansion, so do so in a subroutine.)
CALL :print_line
)
ENDLOCAL
GOTO :EOF
REM Reads !line! variable and strips quotes from it.
:strip_quotes
SETLOCAL EnableDelayedExpansion
SET line=!line:^"=!
REM Make the variable out of SETLOCAL
REM I'm expecting you know how this works:
REM (You may use ampersand instead:
REM `ENDLOCAL & SET "line=%line%"`
REM I just present another way that works.)
(
ENDLOCAL
SET "line=%line%"
)
GOTO :EOF
:print_line
SETLOCAL EnableDelayedExpansion
ECHO !line!
ENDLOCAL
GOTO :EOF
The delims^=^ eol^= in the code above probably needs explanation:
This effectively disables both "delims" characters (i.e. field separators) and "eol" character (i.e. comment character). Without it, the "delims" will default to tab and space and "eol" defaults to a semicolon.
The eol= token always read whichever the next character it is after the equal sign. To disable it this token has to be in the end of the options string so that no character may be used for "eol", effectively disabling it. If the options string is quoted, it might use quotation mark (") as the "eol", so we must not quote the options string.
The delims= option, when it's not the last option in the options string, will be terminated by a space. (To include space in "delims" it has to be the last option of FOR /F options.) So delims= followed by a space and then another option disables the "delims".
I know that it is not actually for the author, but if you need to send some text to the file without quotes - the solution below works for me. You do not need to use quotes in the echo command, just surround the complete command with brackets.
(
echo first very long line
echo second very long line with %lots% %of% %values%
) >"%filename%"
This worked for me:
SET "SOMETHING=Complex (String) (of stuff!)"
echo !SOMETHING! >> file.txt
This will turn "C:\Program Files\somefile.txt" into C:\Program Files\somefile.txt
while still preserving cases such as Height=5'6" and Symbols="!##
:DeQuote
SET _DeQuoteVar=%1
CALL SET _DeQuoteString=%%!_DeQuoteVar!%%
IF [!_DeQuoteString:~0^,1!]==[^"] (
IF [!_DeQuoteString:~-1!]==[^"] (
SET _DeQuoteString=!_DeQuoteString:~1,-1!
) ELSE (GOTO :EOF)
) ELSE (GOTO :EOF)
SET !_DeQuoteVar!=!_DeQuoteString!
SET _DeQuoteVar=
SET _DeQuoteString=
GOTO :EOF
Example
SetLocal EnableDelayedExpansion
set _MyVariable = "C:\Program Files\ss64\"
CALL :dequote _MyVariable
echo %_MyVariable%
The above answer (starting with :DeQuote) assumes delayed environment variable expansion is set to on. From cmd /?:
Delayed environment variable expansion is NOT enabled by default. You
can enable or disable delayed environment variable expansion for a
particular invocation of CMD.EXE with the /V:ON or /V:OFF switch. You
can enable or disable completion for all invocations of CMD.EXE on a
machine and/or user logon session by setting either or both of the
following REG_DWORD values in the registry using REGEDT32.EXE:
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion
and/or
HKEY_CURRENT_USER\Software\Microsoft\Command Processor\DelayedExpansion
to either 0x1 or 0x0. The user specific setting takes precedence over
the machine setting. The command line switches take precedence over the
registry settings.
If delayed environment variable expansion is enabled, then the exclamation
character can be used to substitute the value of an environment variable
at execution time.
The following batch file starts a series of programs with a delay after each one.
The problem is to pass a command line with parameters for each program. This requires quotes around the program argument, which are removed when the call is made. This illustrates a few techniques in batch file processing.
Look in the local subroutine :mystart for how an argument in quotes is passed in, and the quotes are removed.
#echo off
rem http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/if.mspx?mfr=true
rem Start programs with delay
rem Wait n seconds
rem n number retries to communicate with the IP address
rem 1000 milliseconds between the retries
rem 127.0.0.1 is the LocalHost
rem start /b (silent) /min (minimized) /belownormal (lower priority)
rem /normal provides a no-op switch to hold the place of argument 1
rem start /normal "Opinions" %SystemRoot%\explorer.exe /e,d:\agar\jobs\opinion
rem ping 127.0.0.1 -n 8 -w 1000 > nul
rem Remove quotes in Batch
rem http://ss64.com/nt/syntax-dequote.html
rem String manipulation in Batch
rem http://www.dostips.com/DtTipsStringManipulation.php
rem ^ line continuation
rem
rem set p="One Two" p has the exact value "One Two" including the quotes
rem set p=%p:~1,-1% Removes the first and last characters
rem set p=%p:"=% Removes all double-quotes
rem set p=%p:cat=mouse% Replaces cat with mouse
rem ping 127.0.0.1 -n 12 -w 1000 > nul
rem 1 2 3 4
#echo on
call :mystart /b/min "Opinions" "%SystemRoot%\explorer.exe /e,d:\agar\jobs\opinion" 8
#echo on
call :mystart /b/min "Notepad++" D:\Prog_D\Notepad++\notepad++.exe 14
#echo on
call :mystart /normal "Firefox" D:\Prog_D\Firefox\firefox.exe 20
#rem call :mystart /b/min "ProcessExplorer" D:\Prog_D\AntiVirus\SysInternals\procexp.exe 8
#echo on
call :mystart /b/min/belownormal "Outlook" D:\Prog_D\MSOffice\OFFICE11\outlook.exe 2
#echo off
goto:eof
:mystart
#echo off
rem %3 is "program-path arguments" with the quotes. We remove the quotes
rem %4 is seconds to wait after starting that program
set p=%3
set p=%p:"=%
start %1 %2 %p%
ping 127.0.0.1 -n %4 -w 1000 > nul
goto:eof
Using the FOR command to strip the surrounding quotation marks is the most efficient way I've found to do this. In the compact form (Example 2) it's a one-liner.
Example 1: The 5-line (commented) solution.
REM Set your string
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
REM Echo your string into the FOR loop
FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO (
REM Use the "~" syntax modifier to strip the surrounding quotation marks
ECHO %%~A
)
Example 2: The 1-liner real-world example.
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
FOR /F "usebackq tokens=*" %%A IN (`ECHO %STR%`) DO #ECHO %%~A
I find it interesting that the inner echo ignores the redirection characters '<' and '>'.
If you execute ECHO asdfsd>asdfasd you will write file out instead of std out.
Hope this helps :)
Edit:
I thought about it and realized there is an even easier (and less hacky) way of accomplishing the same thing. Use the enhanced variable substitution/expansion (see HELP SET) like this:
SET STR=" <output file> (Optional) If specified this is the name of your edited file"
ECHO %STR:~1,-1%
That will print all but the first and last characters (your quotation marks). I would recommend using SETLOCAL ENABLEDELAYEDEXPANSION too. If you need to figure out where quotation marks are located in the string you can use FINDSTR to get the character #s.
Daniel Budzyński's response is brilliant. It works even in situations where there are special characters in the output. For example:
C:\> for /f "usebackq tokens=2 delims=:" %i in (`%comspec%\..\ping -n 1 -w 200 10.200.1.1 ^| \
findstr /c:"TTL="`) do echo|set /p="%i"
bytes=32 time<1ms TTL=255
If you try tried a simple echo without the quotes, you get a error, due to the "<" in the variable:
C:\> set "output=bytes=32 time<1ms TTL=255"
C:\> echo %output%
The system cannot find the file specified.
C:\> echo|set /p="%output%"
bytes=32 time<1ms TTL=255
Brute force method:
echo "foo <3 bar" | sed -e 's/\(^"\|"$\)//g'
This requires finding a suitable Win32 version of sed, of course.
http://unxutils.sourceforge.net/ is a native win32 port of a bunch of GNU utilities including sed, gawk, grep and wget. (sorry that I don't have enough rep to post this as a comment!)

Resources