Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Batch File Replace Exclamation Mark with Escaped Exclamation Mark

I am working on a batch file that get's data as a variable, and in that variable it has an exclamation mark.

What i am trying to do is add the necessary escape characters to the variable.

"Title":"Turk 182!"

Above is an example of the data I am working with.

setlocal EnableDelayedExpansion
rem replace ! with ^^!
set var=%var:!=^^!!%

But I am not sure that is the correct syntax, since how can i escape an esclamation mark if it's also used as part of the search and replace?

I am trying to replace all esclamation mark with an escaped version so it can be displayed and worked with.

Btw, is there any existing functions in batch that will remove and allow escaping of all special characters?

Here is more code that may help explain what I am doing.

{"Title":"Turk 182!","Year":"1985","Rated":"PG-13","Released":"15 Feb 1985","Runtime":"1 h 42 min","Genre":"Action, Comedy, Drama","Director":"Bob Clark","Writer":"Denis Hamill, James Gregory Kingston","Actors":"Timothy Hutton, Robert Urich, Kim Cattrall, Robert Culp","Plot":"Jimmy Lynch is angry because his older brother, who was injured as a result of an off duty fire rescue...","Poster":"http://ia.media-imdb.com/images/M/MV5BMTQ2OTk1ODA1MV5BMl5BanBnXkFtZTcwNjYwNjgyMQ@@._V1_SX300.jpg","imdbRating":"5.7","imdbVotes":"2,360","imdbID":"tt0090217","Response":"True"}

rem removes starting and ending brackets
set json=%json:~1,-1%
setlocal EnableDelayedExpansion
rem replace "," with linebreak
set json=!json:","="#"!
setlocal EnableDelayedExpansion
rem replace ! with ^^!
set json=%json:!=^^!!%

setlocal DisableDelayedExpansion
echo %json%
echo.
exit /b

Then i place the json variable in the loop and it error's out instead of the true value I just see the actual replace command i used above.

like image 896
crosenblum Avatar asked Nov 13 '12 04:11

crosenblum


People also ask

How do I get rid of the exclamation mark in CMD?

Jaime Ramos sent me this link where the solution can be found: use ^^! . The trick is that a single caret will be used to escape the exclamation mark in the first "pass" of command line interpretation, but delayed variable expansion adds a second "pass" where the exclamation mark will be interpreted.

What does %% mean in batch script?

Represents a replaceable parameter. Use a single percent sign ( % ) to carry out the for command at the command prompt. Use double percent signs ( %% ) to carry out the for command within a batch file. Variables are case sensitive, and they must be represented with an alphabetical value such as %a, %b, or %c. ( <set> )

What is %~ n0 in batch file?

%0 is the name of the batch file. %~n0 Expands %0 to a file Name without file extension.


4 Answers

I'm not convinced you really need to escape !. It is possible to do, but as jeb tried to explain, it can get complicated.

Based on the code you provided, it looks to me like you do not understand what delayed expansion does. I suggest you type HELP SET from a command prompt and read the documentation. The description of delayed expansion begins about half way down with the line that reads "Finally, support for delayed environment variable expansion..."

There are other major benefits to delayed expansion. One of the biggest advantages is you never have to worry about escaping any special characters when you use delayed expansion. Escaping characters while using normal expansion is a pain, and can be extremely confusing until you gain experience. (It really is logical and predictable, but until you understand it, it looks like gibberish)

The biggest problem with delayed expansion is it does not play nice with FOR loops when the data contains !. That is because the delayed expansion occurs after the FOR variable is expanded, so values containing ! will be corrupted. In my json parser below, I toggle the delayed expansion off within the loop to avoid that problem.

I don't know much about json, so my solution below may be naive (incomplete). But here is a simple json parser that works with the data you provided. I put your json string in a file named "test.txt"

@echo off
setlocal disableDelayedExpansion
setlocal enableDelayedExpansion

::Read the json string from a file
<test.txt set /p "json="

::Define LF variable to contain a linefeed
set LF=^


::The above 2 blank lines are critical - DO NOT REMOVE

::Strip the enclosing braces
set "json=!json:~1,-1!"

::Substitute a linefeed for ","
for %%A in ("!LF!") do set "json=!json:","=%%~A!"

::Substitute = for ":"
set "json=!json:":"==!"

::Remove remaining "
set "json=!json:"=!"

::Loop through the data, creating variables of the form var_name=value
for /f "delims=" %%A in ("!json!") do (

  REM If delayed expansion is enabled then endlocal to get back to disabled state
  if "!!" equ "" endlocal

  REM Create the variable
  set "var_%%A"
)

::Display the results - list all variables that begin with var_
set var_

Here is the output

var_Actors=Timothy Hutton, Robert Urich, Kim Cattrall, Robert Culp
var_Director=Bob Clark
var_Genre=Action, Comedy, Drama
var_imdbID=tt0090217
var_imdbRating=5.7
var_imdbVotes=2,360
var_Plot=Jimmy Lynch is angry because his older brother, who was injured as a result of an off duty fire rescue...
var_Poster=http://ia.media-imdb.com/images/M/MV5BMTQ2OTk1ODA1MV5BMl5BanBnXkFtZTcwNjYwNjgyMQ@@._V1_SX300.jpg
var_Rated=PG-13
var_Released=15 Feb 1985
var_Response=True
var_Runtime=1 h 42 min
var_Title=Turk 182!
var_Writer=Denis Hamill, James Gregory Kingston
var_Year=1985
like image 68
dbenham Avatar answered Nov 02 '22 23:11

dbenham


If you are enable delayed expansion, you shouldn't use percent expansion with special characters.
If you are using delayed expansion instead you don't get problems with exclamation marks or other characters.

set myTitle="Turk 182!"
setlocal EnableDelayedExpansion
echo Title=!myTitle!

You could replace the exclamation marks, but you need mutliple carets and the count depends on many things.

  • Is the exclamation mark inside quotes?
  • Do you echo it directly or do you want to copy from one variable to another and echo it then?
  • How to compare it against another value.

As small sample why percent expansion isn't the best choice

@echo off
set test1=An exclamation mark^^^^!
setlocal EnableDelayedExpansion
set test2=An exclamation mark^^^^^^^^^^!
set "test3=An exclamation mark^^^^^!"
set test4a=An exclamation mark^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!
set test4b=%test4a%!
echo %test1%
echo %test2%
echo %test3%
echo %test4b%

If you want to read text from a file in a secure way, you can use the delayed toggling technic.

setlocal DisableDelayedExpansion
for /F "delims=" %%a in (myFile.txt) DO (
  set "line=%%a"
  setlocal EnableDelayedExpansion
  echo !line!
  endlocal
)
like image 33
jeb Avatar answered Nov 03 '22 01:11

jeb


you can use PowerShell:

$json=@"
  {"Title":"Turk 182!","Year":"1985","Rated":"PG-13","Released":"15 Feb 1985","Runtime":"1 h 42 min","Genre":"Action, Comedy, Drama","Director":"Bob Clark","Writer":"Denis Hamill, James Gregory Kingston","Actors":"Timothy Hutton, Robert Urich, Kim Cattrall, Robert Culp","Plot":"Jimmy Lynch is angry because his older brother, who was injured as a result of an off duty fire rescue...","Poster":"http://ia.media-imdb.com/images/M/MV5BMTQ2OTk1ODA1MV5BMl5BanBnXkFtZTcwNjYwNjgyMQ@@._V1_SX300.jpg","imdbRating":"5.7","imdbVotes":"2,360","imdbID":"tt0090217","Response":"True"}
"@

add-type -assembly system.web.extensions
$jserial = new-Object Web.Script.Serialization.JavaScriptSerializer
$jserial.DeserializeObject($json)

Key                                                         Value
---                                                         -----
Title                                                       Turk 182!
Year                                                        1985
Rated                                                       PG-13
Released                                                    15 Feb 1985
Runtime                                                     1 h 42 min
Genre                                                       Action, Comedy, Drama
Director                                                    Bob Clark
Writer                                                      Denis Hamill, James Gregory Kingston
Actors                                                      Timothy Hutton, Robert Urich, Kim Cattrall, Robert Culp
Plot                                                        Jimmy Lynch is angry because his older brother, who was ..
Poster                                                      http://ia.media-imdb.com/images/M/MV5BMTQ2OTk1ODA1MV5BMl..
imdbRating                                                  5.7
imdbVotes                                                   2,360
imdbID                                                      tt0090217
Response                                                    True

or with PowerShell v3:

PS III> $json | ConvertFrom-JSON

Key                                                         Value
---                                                         -----
Title                                                       Turk 182!
Year                                                        1985
Rated                                                       PG-13
Released                                                    15 Feb 1985
Runtime                                                     1 h 42 min
Genre                                                       Action, Comedy, Drama
Director                                                    Bob Clark
Writer                                                      Denis Hamill, James Gregory Kingston
Actors                                                      Timothy Hutton, Robert Urich, Kim Cattrall, Robert Culp
Plot                                                        Jimmy Lynch is angry because his older brother, who was ..
Poster                                                      http://ia.media-imdb.com/images/M/MV5BMTQ2OTk1ODA1MV5BMl..
imdbRating                                                  5.7
imdbVotes                                                   2,360
imdbID                                                      tt0090217
Response 
like image 38
walid2mi Avatar answered Nov 03 '22 01:11

walid2mi


jeb and dbenham fully answered the question already, so this is somewhat off topic...

I used a small trick to avoid the hassle of remember how many carets I must insert in order to use an exclamation mark in diverse situations. I define a variable with Delayed Expansion disabled and assign to it an exclamation mark (I called it bang). Then I Enable Delayed Expansion and use it as !bang!. This way, this value will always appear as an exclamation mark and it is very easy to write...

@echo off
setlocal DisableDelayedExpansion
set bang=!
setlocal EnableDelayedExpansion
echo Yes, it works!bang!

Antonio

like image 34
Aacini Avatar answered Nov 03 '22 00:11

Aacini