Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Echo exact string in windows batch file?

I'm trying to echo a string stored in a variable but it seems to require a lot of escaping. I'm trying with the following code:

setlocal EnableDelayedExpansion
@echo off
set "grass=@##&!$^&%**(&)"
echo !grass!

I want to echo the variable grass verbatim so I see a @##&!$^&%**(&) in the output. What should be done? Thanks!

like image 506
user1077213 Avatar asked Mar 18 '12 10:03

user1077213


People also ask

What does @echo off do in a batch file?

To prevent echoing a particular command in a batch file, insert an @ sign in front of the command. To prevent echoing all commands in a batch file, include the echo off command at the beginning of the file.

What does %% mean in batch script?

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> )

How do I echo the value of a variable in CMD?

To reference a variable in Windows, use %varname% (with prefix and suffix of '%' ). For example, you can use the echo command to print the value of a variable in the form " echo %varname% ".

How do I make a batch file echo?

To create a Windows batch file, follow these steps: Open a text file, such as a Notepad or WordPad document. Add your commands, starting with @echo [off], followed by, each in a new line, title [title of your batch script], echo [first line], and pause. Save your file with the file extension BAT, for example, test.


2 Answers

echo !grass! will always echo the current value verbatim, without the need of any escaping. Your problem is, the value is not what you think it is! The problem is occurring when you are trying to SET the value.

The correct escape sequence to set your value is

set "grass=@##&^!$^^&%%**(&)"

And now for the explanation. The information you need is buried in How does the Windows Command Interpreter (CMD.EXE) parse scripts?. But it is a bit hard to follow.

You have two problems:

1) % must be escaped as %% for each time the line will be parsed. The presence or absence of quotes makes no difference. The delayed expansion state also makes no difference.

 set pct=%
 :: pct is undefined

 set pct=%%
 :: pct=%

 call set pct=%%
 :: pct is undefined because the line is parsed twice due to CALL

 call set pct=%%%%
 :: pct=%

2) A ! literal must be escaped as ^! whenever it is parsed by the delayed expansion phase of the parser. If a line contains ! anywhere within it during delayed expansion, then a ^ literal must be escaped as ^^. But the ^ must also be either quoted or escaped as ^^ for the special character phase of the parser. This can be further complicated by the fact that a CALL will double up any ^ characters. (Sorry, it is very difficult to describe the problem, and the parser is complicated!)

setlocal disableDelayedExpansion

set test=^^
:: test=^

set "test=^"
:: test=^

call set test=^^
:: test=^
:: 1st pass - ^^ becomes ^
:: CALL doubles ^, so we are back to ^^
:: 2nd pass - ^^ becomes ^

call set "test=^"
:: test=^^ because of CALL doubling. There is nothing that can prevent this.

set "test=^...!"
:: test=^...!
:: ! has no impact on ^ when delayed expansion is disabled

setlocal enableDelayedExpansion

set "test=^"
:: test=^
:: There is no ! on the line, so no need to escape the quoted ^.

set "test=^!"
:: test=!

set test=^^!
:: test=!
:: ! must be escaped, and then the unquoted escape must be escaped

set var=hello
set "test=!var! ^^ ^!"
:: test=hello ^ !
:: quoted ^ literal must be escaped because ! appears in line

set test=!var! ^^^^ ^^!
:: test=hello ^ !
:: The unquoted escape for the ^ literal must itself be escaped
:: The same is true for the ! literal

call set test=!var! ^^^^ ^^!
:: test=hello ^ !
:: Delayed expansion phase occurs in the 1st pass only
:: CALL doubling protects the unquoted ^ literal in the 2nd pass

call set "test=!var! ^^ ^!"
:: test=hello ^^ !
:: Again, there is no way to prevent the doubling of the quoted ^ literal
:: when it is passed through CALL
like image 178
dbenham Avatar answered Sep 16 '22 23:09

dbenham


As dbenham said, it's only the assignment.
You could use the escaping like dbenham showed, it's necessary as EnableDelayedExpansion is active while you set the value.
Therefore you need to escape the exclamation mark and the caret must be escaped as there is one exclamation mark in the line, quotes are useless in that situation.
But you could also set the value before you activate the EnableDelayedExpansion,
Then you didn't need the carets.

like image 37
jeb Avatar answered Sep 17 '22 23:09

jeb