83

When I have setlocal ENABLEDELAYEDEXPANSION set in a cmd script is there any way I can escape a ! that I want to use as a parameter to a command?

@echo off
setlocal ENABLEDELAYEDEXPANSION
echo I want to go out with a bang!
echo I still want to go out with a bang^!
jeb
  • 78,592
  • 17
  • 171
  • 225
Andy Morris
  • 3,393
  • 1
  • 21
  • 20

4 Answers4

96

That's what I found (^^)

@echo off
setlocal ENABLEDELAYEDEXPANSION
echo I want to go out with a bang^^!
FrVaBe
  • 47,963
  • 16
  • 124
  • 157
  • 3
    Btw, if you had to replace an exclamation mark inside a variable how would you do that? – crosenblum Nov 12 '12 at 01:04
  • 2
    @crosenblum I would recommend to ask this as an own question. Than it will be visbile for all SO members and most likely answered. – FrVaBe Nov 12 '12 at 08:44
  • 1
    This (nor the other solutions) will work if the exclamation mark is inside a variable that you set/use or pass on to a call-label, in which case I think you'll be out of luck. – Abel Sep 28 '17 at 03:57
74

An additional remark to the answer of FrVaBe.

Normally the ^^! works, but in quotes you only need ^! instead.

echo I want to go out with a bang^^!
echo He said "Bang^!"

This is a result of the escape mechanism of the batch parser.

First the parser parses a line and the caret escapes the next character, in this case it has an effect for &|<>()"<linefeed>, but only outside of quotes, as inside of the quotes all characters are "normal" and the caret itself has no effect.

With delayed expansion an extra parse step follows, there is the caret also an escape character for the next character, but only affects the ! and ^, and quotes are ignored in this parsing step. This extra step will be executed only, if there is at least one ! in the line.

setlocal DisableDelayedExpansion
echo DisableDelayedExpansion
echo one caret^^
echo one caret^^  bang! "boom^!"

echo(
setlocal EnableDelayedExpansion
echo EnableDelayedExpansion
echo one caret^^
echo none caret^^  bang^^! "boom^!"

---- OUTPUT ------

DisableDelayedExpansion
one caret^
one caret^  bang! "boom^!"

EnableDelayedExpansion
one caret^
none caret  bang! "boom!"


EDIT

Here is a slightly modified example that better illustrates the various escape permutations that are required, depending on the context. The only case that requires unusual escaping is the last example when delayed expansion is on and there exists at least one ! on the line.

@echo off
setlocal DisableDelayedExpansion
echo DisableDelayedExpansion
echo caret^^       "caret^"
echo caret^^ bang! "caret^ bang!"

echo(
setlocal EnableDelayedExpansion
echo EnableDelayedExpansion
echo caret^^       "caret^"
echo caret^^^^ bang^^! "caret^^ bang^!"

-- OUTPUT --

DisableDelayedExpansion
caret^       "caret^"
caret^ bang! "caret^ bang!"

EnableDelayedExpansion
caret^       "caret^"
caret^ bang! "caret^ bang!"
Community
  • 1
  • 1
jeb
  • 78,592
  • 17
  • 171
  • 225
17

To use an explanation point in batch with Delayed Expansion enabled, you must first add the explanation point to a variable with it disabled. See the below example with both DISABLEDELAYEDEXPANSION and ENABLEDELAYEDEXPANSION state.

@echo off
setlocal DISABLEDELAYEDEXPANSION
set DB_password=encrypt!Pws
echo %DB_password%
SETLOCAL ENABLEDELAYEDEXPANSION
echo !DB_password!
Neuron
  • 5,141
  • 5
  • 38
  • 59
Aditya Sharma
  • 186
  • 1
  • 2
  • Best answer! This solves the use in scripts where DELAYEDEXPANSION is needed. – JasonXA Jun 07 '17 at 08:51
  • That's aberrative. Nowhere in the requirements is memory a concern and yet I use it a lot with no ill effect. Unless you can actually contribute, keep your nonsense to yourself. – JasonXA Jan 10 '18 at 04:36
  • I actually wrote my code like yours, then thought "this cannot work, because the ! will be lost with delayedExpansion enabled", searched the whole internet for an solution, landed here, read the last answer and found out, that my code would have worked all the time, I just didn't realized it only gets replaced once... Thanks a lot ^!^! ;D – timlg07 Oct 21 '18 at 18:31
6

Thanks. To add to this valuable point, if one's script contains a variable whose value contains an "!", then the following approach will render that value as-is:

@echo off
SETLOCAL EnableDelayedExpansion
set /P omg=Enter a value that contains an exclamation-point:
echo Traditional: %omg%
echo Alternative: !omg!
pause