How do you strip quotes out of an ECHO'ed string in a Windows batch file?
Solution 1
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.
Solution 2
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
Solution 3
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%
Solution 4
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 ofFOR /F
options.) Sodelims=
followed by a space and then another option disables the "delims".
Solution 5
This worked for me:
SET "SOMETHING=Complex (String) (of stuff!)"
echo !SOMETHING! >> file.txt
Related videos on Youtube
Lance Roberts
Control Systems Engineer. Most people want to stick their head in the sand and ignore problems, in an effort to avoid conflict. I refuse to be that passive person. Problems are there to be fixed, which means that first they have to identified. Denial is not just a river in Egypt.
Updated on October 12, 2021Comments
-
Lance Roberts over 2 years
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.
-
Greg Hewgill about 15 yearsGood idea, I would recommend unxutils over cygwin for most situations.
-
Richard A about 15 years'The above' here refers to JRL's answer.
-
Richard A about 15 yearsThis could be simplifed by using setlocal and endlocal rather than dereferencing the two local variables. I prefer my solution, though.
-
Rich about 15 yearsFor a single batch you should probably rather use setlocal enabledelayedexpansion. No need to mess around in the registry or tell users how to call cmd.
-
BHARATHWAJ almost 15 yearsThanks for the 'setlocal' tip, didn't know that one.
-
Jens Schauder almost 15 yearsGreat! Is there a similar easy way to strip the quotes when providing a parameter? For the case where we have control only over the calling side, but not the script processing the parameter?
-
Richard A almost 15 yearsWould it be sufficient to wrap your call in your own routine that did the stripping, as above, before doing the call?
-
Jim2B almost 8 yearsInterestingly this does not work for me. set thestring=%~1 yields "The syntax of the command is incorrect.", even when I use identical syntax to that shown by Richard and also despite seeing the same text in the "call /?" section.
-
Jim2B almost 8 yearsThe problem is in my text. It is xml and has "<" & ">" in it. So Richard's solution does work, I just need to figure out another means of manipulating that text.
-
Richard A almost 8 yearsThat's a tricky one, @Jim2B, you might be able to escape the < and > with ^ before it gets into batch land. It depends upon your context.
-
Jim2B almost 8 yearsRichard, what I eventually did was store the text I needed in a separate file and then performed "type file.txt >> output.txt". It seems like this successfully passes the ">" & "<" without any attempt at interpretation. Even when I tried using the "^<" syntax, it still didn't like something in the string and I didn't have the time to work out the exact issue.
-
Richard A almost 8 years@Jim2B sometimes life is just too short. I'm glad you solved it, one way or another.
-
HardcoreHenry over 5 yearsHi, and welcome to SO -- This would fit better in a comment than in an answer (though being a new contributor, you likely don't have permissions to write comments). Regardless, please see stackoverflow.com/help/how-to-answer for guidelines for answers.
-
PeterCo over 3 yearsI don't think that this works for a STR like
"This & That"
-
Tzunghsing David Wong over 2 yearsAfter adding
SETLOCAL ENABLEDELAYEDEXPANSION
first, this solution works for me (on Windows 10 cmd.exe) -
Mike Q over 2 yearsI should have mentioned that was required because of the !VARIABLE! instead of %VARIABLE%
-
Michael Burr about 2 yearsNIce trick. But terrible that MS's irresponsible, ad hoc approach to the cmd.exe batch language makes these kinds of hacks necessary.