89

This maybe really easy but there were no answers for it over the net. I want to echo a XML line via batch into a file but it misunderstands the XML closing tag for redirection ">". The line is as follows:

echo <?xml version="1.0" encoding="utf-8" ?> > myfile.xml

is there any way to give a hint to batch parser not to interpret a special string? I used double-quotes but it writes them to the file as well! The file should look like this after echo:

<?xml version="1.0" encoding="utf-8" ?>
aschipfl
  • 33,626
  • 12
  • 54
  • 99
Amir Zadeh
  • 3,481
  • 2
  • 26
  • 47
  • 3
    possible duplicate of [Escape angle brackets in a Windows command prompt](http://stackoverflow.com/questions/251557/escape-angle-brackets-in-a-windows-command-prompt) – Helen Sep 05 '11 at 13:26
  • 1
    Possible duplicate of [Batch character escaping](http://stackoverflow.com/questions/6828751/batch-character-escaping) – phuclv Mar 15 '17 at 10:05
  • 1
    Possible duplicate of [Escape angle brackets in a Windows command prompt](https://stackoverflow.com/questions/251557/escape-angle-brackets-in-a-windows-command-prompt) – phuclv Sep 29 '18 at 03:07

8 Answers8

138

You can escape shell metacharacters with ^:

echo ^<?xml version="1.0" encoding="utf-8" ?^> > myfile.xml

Note that since echo is a shell built-in it doesn't follow the usual conventions regarding quoting, so just quoting the argument will output the quotes instead of removing them.

Joey
  • 344,408
  • 85
  • 689
  • 683
  • 4
    @Nevin: You still have to escape each and every `<` and `>`. Nothing special there. That being said, I'd advise against `echo`ing large XML files on a single line for ... kinda obvious reasons. – Joey Feb 24 '15 at 07:36
  • :Sorry to ask again..It's not working for me... Code is given below. Sorry for not giving the code in correct format echo ^ ^ ^ ^ ^ ^ ^ >MyFile.xml – Nevin Raj 1 hour ago – Nevin Raj Victor Feb 24 '15 at 08:58
  • 1
    @Nevin: There are semicolons in there that should not be there. Apart from that it produces valid XML for me. – Joey Feb 24 '15 at 09:48
  • You were absolutely correct..The semicolon caused the trouble..Thanks – Nevin Raj Victor Feb 25 '15 at 04:50
  • 6
    Not needing to batch very often, I keep forgetting my top 5 illegal `echo` characters: `<`, `>`, `'`, `(` and `)`. All can be delimited with a caret `^`. More illegal characters [here](http://www.robvanderwoude.com/escapechars.php) but most of them aren't in my typical use case. – Rich C Apr 25 '15 at 03:28
32

In order to use special characters, such as '>' on Windows with echo, you need to place a special escape character before it.

For instance

echo A->B

will not work since '>' has to be escaped by '^':

 echo A-^>B

See also escape sequences. enter image description here

There is a short batch file, which prints a basic set of special character and their escape sequences.

orbitcowboy
  • 1,438
  • 13
  • 25
  • 2
    But for quotes, the caret is the escape character, using two quotes is wrong, as it adds simply a second quote. `echo Line1"" & echo line2` vs `echo Line1^" & echo line2` – jeb Nov 23 '15 at 11:51
  • 1
    Thanks for providing the table of examples. It helped me with multiple characters. – Ben Oct 26 '20 at 15:01
22

One easy solution is to use delayed expansion, as this doesn't change any special characters.

set "line=<?xml version="1.0" encoding="utf-8" ?>"
setlocal EnableDelayedExpansion
(
  echo !line!
) > myfile.xml

EDIT : Another solution is to use a disappearing quote.

This technic uses a quotation mark to quote the special characters

@echo off
setlocal EnableDelayedExpansion
set ""="
echo !"!<?xml version="1.0" encoding="utf-8" ?>

The trick works, as in the special characters phase the leading quotation mark in !"! will preserve the rest of the line (if there aren't other quotes).
And in the delayed expansion phase the !"! will replaced with the content of the variable " (a single quote is a legal name!).

If you are working with disabled delayed expansion, you could use a FOR /F loop instead.

for /f %%^" in ("""") do echo(%%~" <?xml version="1.0" encoding="utf-8" ?>

But as the seems to be a bit annoying you could also build a macro.

set "print=for /f %%^" in ("""") do echo(%%~""

%print%<?xml version="1.0" encoding="utf-8" ?>
%print% Special characters like &|<>^ works now without escaping
jeb
  • 78,592
  • 17
  • 171
  • 225
  • 1
    `echo !line!` will work as long as there are no `!` in the `line` variable. Any remedy for that? – Davor Josipovic Sep 21 '15 at 09:40
  • 3
    No, if `line` contains a `!` then it will work without any problems, but it's not always obvious how to get the exclamation marks into the variable. Try `set "line=Hello^!" & echo !line!` – jeb Sep 21 '15 at 10:22
  • you are 100% correct. I must have looked over something! – Davor Josipovic Sep 21 '15 at 11:04
22

another method:

@echo off

for /f "useback delims=" %%_ in (%0) do (
  if "%%_"=="___ATAD___" set $=
  if defined $ echo(%%_
  if "%%_"=="___DATA___" set $=1
)
pause
goto :eof

___DATA___
<?xml version="1.0" encoding="utf-8" ?>
 <root>
   <data id="1">
      hello world
   </data>
 </root>
___ATAD___


rem # 
rem # 
walid2mi
  • 2,704
  • 15
  • 15
  • Nice idea, to add data in a script! – yO_ Mar 27 '19 at 13:08
  • Nice solution to unpack a text file from a batch file. The line `if defined $ echo(%%_` should be extended to `if defined $ echo(%%_ >> myxmlfile.xml` to copy the output into a file. – PMF Oct 10 '19 at 11:26
  • 1
    can we have variables inside ```__DATA__```? – bilogic Jul 11 '20 at 07:34
11

The way to output > character is to prepend it with ^ escape character:

echo ^>

will print simply

>
Aleks G
  • 56,435
  • 29
  • 168
  • 265
3

The answer from Joey was not working for me. After executing

  echo ^<?xml version="1.0" encoding="utf-8" ?^> > myfile.xml

I got this error bash: syntax error near unexpected token `>'

This solution worked for me:

 echo "<?xml version=\"1.0\" encoding=\"utf-8\">" > myfile.txt

See also http://www.robvanderwoude.com/escapechars.php

Competo
  • 133
  • 1
  • 11
1

Here's one more approach by using SET and FOR /F

@echo off

set "var=<?xml version="1.0" encoding="utf-8" ?>"

for /f "tokens=1* delims==" %%a in ('set var') do echo %%b

and you can beautify it like:

@echo off
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
set "print{[=for /f "tokens=1* delims==" %%a in ('set " & set "]}=') do echo %%b"
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


set "xml_line.1=<?xml version="1.0" encoding="utf-8" ?>"
set "xml_line.2=<root>"
set "xml_line.3=</root>"

%print{[% xml_line %]}%
npocmaka
  • 55,367
  • 18
  • 148
  • 187
-1

the escape character ^ also did not work for me. The single quotes worked for me (using ansible scripting)

shell: echo  '{{ jobid.content }}'

output:

 {
    "changed": true,
    "cmd": "echo  '<response status=\"success\" code=\"19\"><result><msg><line>query job enqueued with jobid 14447</line></msg><job>14447</job></result></response>'",
    "delta": "0:00:00.004943",
    "end": "2020-07-31 08:45:05.645672",
    "invocation": {
        "module_args": {
            "_raw_params": "echo  '<response status=\"success\" code=\"19\"><result><msg><line>query job enqueued with jobid 14447</line></msg><job>14447</job></result></response>'",
            "_uses_shell": true,
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": null,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true,
            "warn": true
        }
    },
    "rc": 0,
    "start": "2020-07-31 08:45:05.640729",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "<response status=\"success\" code=\"19\"><result><msg><line>query job enqueued with jobid 14447</line></msg><job>14447</job></result></response>",
    "stdout_lines": [
        "<response status=\"success\" code=\"19\"><result><msg><line>query job enqueued with jobid 14447</line></msg><job>14447</job></result></response>"
    ]
Stephan
  • 53,940
  • 10
  • 58
  • 91