Строка строки командной строки Windows удаляет "!"

У меня есть этот маленький фрагмент, который заменяет production:false with production:true.

(FOR /F "tokens=1,* delims=]" %%A in ('"type test.js|find /n /v """') do (

 set "line=%%B"

 if defined line (
 call set "line=echo.%%line:production:false=production:true%%"
 FOR /F "delims=" %%X in ('"echo."%%line%%""') do %%~X
 ) ELSE echo.

)) >test-temp.js

move /Y test-temp.js test.js

Пока все хорошо, но в test.js говорится что-то вроде:

if ( !production ) {}

Дело в том, что "!"также удаляется вышеуказанной командой. Любая идея, как это происходит?

3 ответа

Вы, вероятно, delayedexpansion.

Запуск вашего фрагмента (который вы даете нам) против вашей отдельной строки предоставленных данных просто воспроизводил строку данных дословно.

с delayedexpansion ! как вы описали.

delayedexpansiondelayedexpansion в действии

SETLOCAL DISABLEDELAYEDEXPANSION
(FOR /F "tokens=1,* delims=]" %%A in ('"type q19406461.txt|find /n /v """') do (
 set "line=%%B"

 if defined line (
 call set "line=echo.%%line:production:false=production:true%%"
 FOR /F "delims=" %%X in ('"echo."%%line%%""') do %%~X
 ) ELSE echo.

)) >test-temp.js
ENDLOCAL


Питер уже поставил диагноз проблемы с задержкой расширения. Вот немного больше объяснений.

FOR переменные расширены до замедленного расширения. Поэтому строка set "line=%%B" сначала устанавливает значение if ( !production ) {}, но затем отложенное расширение видит непарный ! и полоски его. Если он был спарен, он попытался бы расширить переменную между ними.

Вот краткое описание порядка разброса переменных (практическое, но немного неточное):

1) Нормальное расширение: аргумент (% 1) и переменная (% var%). Аргументы имеют приоритет над переменными.

2) ДЛЯ переменной: %% A

3) Отсроченное расширение:! Var!

4) Переменные SET/A

Смотрите, как интерпретатор команд Windows (CMD.EXE) анализирует сценарии для более точного описания того, как строки анализируются и расширяются.

Возможно использование замедленного расширения в вашем цикле без развращения ! литералы, если вы включаете и выключаете замедленное расширение. Это предпочтительнее использовать синтаксис CALL, потому что он быстрее, не гасит с % литералов, не имеет двойных кавычек, защищает от всех ядовитых символов, даже если они не цитируются.

Использование замедленного расширения делает код намного проще, быстрее и надежнее:

setlocal disableDelayedExpansion
(FOR /F "tokens=1,* delims=]" %%A in ('"type test.js|find /n /v """') do (
 set "line=%%B"
 setlocal enableDelayedExpansion
 if defined line (
 echo(!line:production:false=production:true!
 ) ELSE echo(
 endlocal
)) >test-temp.js
move /Y test-temp.js test.js
endlocal

Обратите внимание, что я использую ECHO( вместо ECHO. потому что последний может выйти из строя в некоторых неясных сценариях. ECHO( похоже, что это вызовет проблемы с круглыми скобками, но на самом деле это всегда работает без проблем.

Обратите внимание, что я все равно не буду использовать приведенный выше код. Вместо этого я бы воспользовался утилитой REPL.BAT, как в своем ответе, как foxidrive.


Это надежный метод и использует вспомогательный пакетный файл с именем repl.bat - http://www.dostips.com/forum/viewtopic.php?f=3&t=3855

Поместите repl.bat в ту же папку, что и командный файл.

@echo off
type "test.js"|repl "production:false" "production:true" >"test-temp.js"

licensed under cc by-sa 3.0 with attribution.