echo !grass!
всегда будет отображать текущее значение дословно, без необходимости экранирования. Ваша проблема в том, что ценность не в том, что вы думаете! Проблема возникает, когда вы пытаетесь установить значение.
Правильная escape-последовательность для установки значения:
set "grass=@##&^!$^^&%%**(&)"
А теперь объяснение. Необходимая информация находится в Как синтаксический анализ сценариев интерпретатора команд Windows (CMD.EXE)? . Но это немного трудно следовать.
У вас есть две проблемы:
1) %
необходимо экранировать как %%
для каждого анализа строки. Наличие или отсутствие цитат не имеет значения. Состояние отложенного расширения также не имеет значения.
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) Литерал !
должен быть экранирован как ^!
всякий раз, когда он анализируется фазой отложенного расширения анализатора. Если строка содержит !
где-либо внутри нее во время отложенного расширения, то литерал ^
должен быть экранирован как ^^
. Но ^
также должен быть заключен в кавычки или экранирован как ^^
для фазы специальных символов синтаксического анализатора. Это может быть еще более осложнено тем фактом, что CALL удвоит любые ^
символов. (Извините, описать проблему очень сложно, а синтаксический анализатор сложен!)
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