Как заменить содержимое переменной в пакетном файле Windows
Я пишу простой script для замены текста в переменной среды другим текстом. Проблема, которую я получаю, заключается в замене замещенного или замещенного текста на другие переменные
SET a=The fat cat
ECHO %a%
REM Results in 'The fat cat'
ECHO %a:fat=thin%
REM Results in 'The thin cat'
Прекрасно работает (вывод "Толстый кот" и "Тонкая кошка"
Однако, если "жир" или "тонкий" находятся в переменных, он не работает
SET b=fat
ECHO %a:%c%=thin%
REM _Should_ give 'The thin cat'.
REM _Actually_ gives '%a:fat=thin%' (the %c% is evaluated, but no further).
REM using delayed evaluation doesn't make any difference either
ECHO !a:%c%=thin!
REM Actual output is now '!a:fat=thin!'
Я знаю, что это можно сделать, как я видел это в блогах раньше, но я никогда не сохранял ссылку на блоги.
У кого-нибудь есть идеи?
PS. Я запускаю сценарии в Windows 7
ПФС. Я знаю, что это проще в Perl/Python/другом языке script, но я просто хочу знать, почему что-то, что должно быть легко, не сразу становится очевидным.
PPPS. Я также пробовал сценарии с замедленным расширением, явно включенным
SETLOCAL enabledelayedexpansion
Это не имеет значения.
Ответы
Ответ 1
Попробуйте следующее:
Скопируйте и вставьте код в блокнот и сохраните его в виде пакетного файла.
@echo off
setlocal enabledelayedexpansion
set str=The fat cat
set f=fat
echo.
echo f = [%f%]
echo.
echo str = [%str%]
set str=!str:%f%=thin!
echo str:f=thin = [%str%]
Надеюсь, ты убежден!
Ответ 2
Используйте CALL. Поместите следующее в пакетном режиме script и запустите его:
set a=The fat cat
set b=fat
set c=thin
REM To replace "%b%" with "%c%" in "%a%", we can do:
call set a=%%a:%b%^=%c%%%
echo %a%
pause
Как указано здесь, мы используем тот факт, что:
CALL internal_cmd
...
internal_cmd Запустите внутреннюю команду , сначала развернув любые переменные в аргументе.
В нашем случае internal_cmd изначально устанавливает a = %% a:% b% ^ =% c %%%.
После расширения inner_cmd становится установлено a =% a: fat = thin%.
Таким образом, в нашем случае работает
набор вызовов a = %% a:% b% ^ =% c %%%
эквивалентно запуску:
установите a =% a: fat = thin%.
Ответ 3
Проблема с:
echo %a:%c%=thin%
заключается в том, что он пытается развернуть две переменные: a:
и =thin
с константой c
между ними.
Попробуйте следующее:
echo echo ^%a:%c%=thin^% | cmd
Первая команда выдает:
echo %a:fat=thin%
который передается во вторую командную оболочку для оценки.
Ответ 4
И... Как насчет этого?
@echo off
setlocal enabledelayedexpansion
set str=The fat cat
set f=fat
set t=thin
echo.
echo f = [%f%]
echo t = [%t%]
echo.
echo str = [%str%]
set str=!str:%f%=%t%!
echo str:f=t = [%str%]
Nifty eh?
Ответ 5
Недавно я столкнулся с той же ситуацией... Как было сказано ранее, я использовал, как показано ниже, и работал...
set filearg=C:\data\dev\log\process
set env=C:\data\dev
REM I wanted \log\process as output
SETLOCAL enabledelayedexpansion
set str2=!filearg:%env%=!
echo Output : %str2%
echo.
endlocal
Выход:
\log\process
Это сработало..!!
Ответ 6
Я стараюсь не использовать SETLOCAL enabledelayedexpansion ... ENDLOCAL
все (или почти все) время, потому что обычно я хочу установить или изменить несколько переменных, и я хочу, чтобы новые значения были доступны в других областях script или после пакетный script заканчивается (SETLOCAL | ENDLOCAL забудет о любых новых переменных или изменениях в переменных в "SETLOCAL" части script. Иногда это удобно, но для меня это обычно не так.
В настоящее время я использую метод, описанный @Zuzel, но прежде чем я узнал об этом методе, я использовал его, что очень похоже (но выглядит немного сложнее):
for /F "usebackq delims=" %%f in (`echo set "a=^%a:%b%=%c%^%"`) do @%%f
Пример script:
@echo off
set a=The fat cat
set b=fat
set c=thin
@echo.
@echo before: "%a%"
@echo replace "%b%" with "%c%" in "%a%" using for:
for /F "usebackq delims=" %%f in (`echo set "a=%%a:%b%=%c%%%"`) do @%%f
@echo after for: "%a%"
goto :EOF
вывод из запуска script:
before: "The fat cat"
replace "fat" with "thin" in "The fat cat" using for:
after for: "The thin cat"
Мне нравится этот метод, потому что вы можете вызывать внешние программы (или внутренние команды) с помощью модифицированных переменных, а также захватывать и обрабатывать вывод команды (строка за строкой).
Но метод Zuzel проще и чище для большинства ситуаций, включая тот, который вы описали.
Примечание:
Оба эти метода (а также SETLOCAL enabledelayedexpansion ... ENDLOCAL
, конечно) работают корректно, если они запускаются из пакета script. Если вы попытаетесь использовать любой из этих двух методов ( "вызов" или "для" ) непосредственно в окне командной строки, вы получите что-то отличное от того, что вывод был запущен из script.
Например, запустите это как script:
@echo off
set a=The fat cat
set b=fat
set c=thin
set d=calico
set e=sleepy
@echo.
@echo before: "%a%"
@echo.
@echo replace "%b%" with "%c%" in "%a%" using call:
call set a=%%a:%b%=%c%%%
@echo after call: "%a%" ("%b%" to "%c%")
@echo.
@echo replace "%c%" with "%d%" in "%a%" using for:
for /F "usebackq delims=" %%f in (`echo set "a=%%a:%c%=%d%%%"`) do @%%f
@echo after for: "%a%" ("%c%" to "%d%")
@echo.
@echo replace "%d%" with "%e%" in "%a%" using call:
call set a=%%a:%d%=%e%%%
@echo after call: "%a%" ("%d%" to "%e%")
вывод из запуска script:
before: "The fat cat"
replace "fat" with "thin" in "The fat cat" using call:
after call: "The thin cat" ("fat" to "thin")
replace "thin" with "calico" in "The thin cat" using for:
after for: "The calico cat" ("thin" to "calico")
replace "calico" with "sleepy" in "The calico cat" using call:
after call: "The sleepy cat" ("calico" to "sleepy")
Теперь запустите эти команды непосредственно в окне командной строки:
c:\>
c:\>set a=The fat cat
c:\>set b=fat
c:\>set c=thin
c:\>set d=calico
c:\>set e=sleepy
c:\>
c:\>@echo.
c:\>@echo before: "%a%"
before: "The fat cat"
c:\>@echo.
c:\>
c:\>@echo replace "%b%" with "%c%" in "%a%" using call:
replace "fat" with "thin" in "The fat cat" using call:
c:\>call set a=%%a:%b%=%c%%%
c:\>@echo after call: "%a%" ("%b%" to "%c%")
after call: "%The thin cat%" ("fat" to "thin")
c:\>
c:\>@echo.
c:\>@echo replace "%c%" with "%d%" in "%a%" using for:
replace "thin" with "calico" in "%The thin cat%" using for:
c:\>for /F "usebackq delims=" %f in (`echo set "a=%%a:%c%=%d%%%"`) do @%f
c:\>@echo after for: "%a%" ("%c%" to "%d%")
after for: "%%The calico cat%%" ("thin" to "calico")
c:\>
c:\>@echo.
c:\>@echo replace "%d%" with "%e%" in "%a%" using call:
replace "calico" with "sleepy" in "%%The calico cat%%" using call:
c:\>call set a=%%a:%d%=%e%%%
c:\>@echo after call: "%a%" ("%d%" to "%e%")
after call: "%%%The sleepy cat%%%" ("calico" to "sleepy")
c:\>
проверьте строки до и после вывода из окна командной строки:
before: "The fat cat"
replace "fat" with "thin" in "The fat cat" using call:
after call: "%The thin cat%" ("fat" to "thin")
replace "thin" with "calico" in "%The thin cat%" using for:
after for: "%%The calico cat%%" ("thin" to "calico")
replace "calico" with "sleepy" in "%%The calico cat%%" using call:
after call: "%%%The sleepy cat%%%" ("calico" to "sleepy")
Обратите внимание, что подстановки сделаны правильно, но также замечают, что при запуске этих команд непосредственно в окне командной строки он добавляет набор "%" (знаки процента) до и после ожидаемого значения каждый раз, когда выполняется подстановка, Таким образом, это затрудняет проверку любого из этих методов непосредственно в окне командной строки.
Ответ 7
:: Использовать perl on% var% = ~ s/$old/$new/
set var=The fat cat
set old=fat
set new=thin
ECHO before=%var%
for /f "delims=" %%m in ('echo %var% ^|perl -pe "s/%old%/%new%/" ') do set var=%%m
ECHO after=%var%
Вывод:
before=The fat cat
after=The thin cat