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

74,232

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 of FOR /F options.) So delims= 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
Share:
74,232

Related videos on Youtube

Lance Roberts
Author by

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, 2021

Comments

  • Lance Roberts
    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
    Greg Hewgill about 15 years
    Good idea, I would recommend unxutils over cygwin for most situations.
  • Richard A
    Richard A about 15 years
    'The above' here refers to JRL's answer.
  • Richard A
    Richard A about 15 years
    This could be simplifed by using setlocal and endlocal rather than dereferencing the two local variables. I prefer my solution, though.
  • Rich
    Rich about 15 years
    For 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
    BHARATHWAJ almost 15 years
    Thanks for the 'setlocal' tip, didn't know that one.
  • Jens Schauder
    Jens Schauder almost 15 years
    Great! 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
    Richard A almost 15 years
    Would it be sufficient to wrap your call in your own routine that did the stripping, as above, before doing the call?
  • Jim2B
    Jim2B almost 8 years
    Interestingly 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
    Jim2B almost 8 years
    The 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
    Richard A almost 8 years
    That'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
    Jim2B almost 8 years
    Richard, 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
    Richard A almost 8 years
    @Jim2B sometimes life is just too short. I'm glad you solved it, one way or another.
  • HardcoreHenry
    HardcoreHenry over 5 years
    Hi, 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
    PeterCo over 3 years
    I don't think that this works for a STR like "This & That"
  • Tzunghsing David Wong
    Tzunghsing David Wong over 2 years
    After adding SETLOCAL ENABLEDELAYEDEXPANSION first, this solution works for me (on Windows 10 cmd.exe)
  • Mike Q
    Mike Q over 2 years
    I should have mentioned that was required because of the !VARIABLE! instead of %VARIABLE%
  • Michael Burr
    Michael Burr about 2 years
    NIce trick. But terrible that MS's irresponsible, ad hoc approach to the cmd.exe batch language makes these kinds of hacks necessary.