Как заменить переменное содержимое в командном файле Windows - PullRequest
12 голосов
/ 06 декабря 2010

Я пишу простой скрипт для замены текста в переменной окружения другим текстом.Проблема, которую я получаю, заключается в том, что замещенный или замещенный текст извлекается из других переменных

SET a=The fat cat
ECHO %a%
REM Results in 'The fat cat'
ECHO %a:fat=thin%
REM Results in 'The thin cat'

Работает нормально (выводится «Толстый кот» и «Тонкий кот»

Однако, если'fat' или 'thin' - переменные, они не работают

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

PPS. Я знаю, что это проще в Perl / Python / другом языке сценариеввыбора, но я просто хочу знать, почему что-то, что должно быть легким, не сразу очевидно.

PPPS. Я также пробовал скрипты с явно отложенным расширением

SETLOCAL enabledelayedexpansion

Это не имеет значения.

Ответы [ 7 ]

13 голосов
/ 19 декабря 2010

Пожалуйста, попробуйте следующее:

Скопируйте и вставьте код в Блокнот и сохраните его как пакетный файл.

   @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%]

Надеюсь, вы уверены!

8 голосов
/ 03 ноября 2014

Используйте CALL . Поместите в пакетный скрипт следующее и запустите его:

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 изначально set a = %% a:% b% ^ =% c %%% .

После расширения internal_cmd становится set a =% a: fat = thin% .

Таким образом, в нашем случае работает

набор вызовов a = %% a:% b% ^ =% c %%%

равно эквивалентно для работы:

set a =% a: жир = тонкий% .

2 голосов
/ 19 декабря 2010

И ... Как насчет этого?

@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%]

Отличная а?

2 голосов
/ 06 декабря 2010

Проблема с:

echo %a:%c%=thin%

заключается в том, что он пытается раскрыть две переменные: a: и =thin с постоянной строкой c между ними.

Попробуйте это:

echo echo ^%a:%c%=thin^% | cmd

Первая команда выводит:

echo %a:fat=thin%

, который передается во вторую командную оболочку для оценки.

1 голос
/ 03 мая 2012

Недавно я столкнулся с такой же ситуацией .. Как уже говорилось ранее, я использовал как показано ниже и работал ...

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

Это сработало!!

0 голосов
/ 03 апреля 2017

:: Использовать perl для% 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
0 голосов
/ 03 июля 2016

Я стараюсь избегать использования SETLOCAL enabledelayedexpansion ... ENDLOCAL все (или почти все) время, потому что обычно я хочу установить или изменить несколько переменных и хочу, чтобы новые значения были доступны в других областях скрипта или после пакетасценарий заканчивается (SETLOCAL | ENDLOCAL забудет о любых новых переменных или изменениях переменных в части «SETLOCAL» сценария. Иногда это удобно, но для меня, как правило, нет.

В настоящее время я использую методописывается @ Zuzel , но прежде чем я узнал об этом методе, я использовал его, который очень похож (но выглядит немного сложнее):

for /F "usebackq delims=" %%f in (`echo set "a=^%a:%b%=%c%^%"`) do @%%f

пример сценария:

@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

вывод от запуска сценария:

before: "The fat cat"
replace "fat" with "thin" in "The fat cat" using for:
after for:  "The thin cat"

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

Но метод Зузеля проще и чище для большинства ситуаций, включая описанную вами.

Примечание:

Оба эти метода (и, конечно, SETLOCAL enabledelayedexpansion ... ENDLOCAL) работают корректно, только если они запускаются из пакетного сценария.Если вы попытаетесь использовать любой из этих двух методов («call» или «for») непосредственно в окне командной строки, вы получите нечто отличное от того, что выводился из сценария.

Например,запустите это как скрипт:

@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%")

вывод от запуска скрипта:

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...