2010-12-06 12 views
10

Estoy escribiendo un script simple para sustituir texto en una variable de entorno con otro texto. El problema que tengo es con el sustituido o texto sustituido ser tomado de otras variablesCómo sustituir contenidos de variables en un archivo por lotes de Windows

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

funciona bien (la salida es 'El gato gordo' y 'El gato delgada'

Sin embargo, si 'grasa' o 'delgada' están en las variables, no funciona

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!' 

sé que esto puede hacerse como lo he visto en blogs antes, pero nunca he salvado el enlace a los blogs.

Cualquiera tener alguna idea s?

PS. Estoy ejecutando las secuencias de comandos en Windows 7

PPS. Sé que esto es más fácil en Perl/Python/otro lenguaje de script de elección, pero solo quiero saber por qué algo que debería ser fácil no es inmediatamente obvio.

PPPS. También probé las secuencias de comandos con expansión demorada explícitamente activada

SETLOCAL enabledelayedexpansion 

Esto no hace la diferencia.

Respuesta

11

Por favor, intente lo siguiente:

Copia y pega el código en el Bloc de notas y guardarlo como un archivo por lotes.

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

Espero que estés convencido!

2

El problema:

echo %a:%c%=thin% 

es que se trata de ampliar dos variables: a: y =thin con una cadena constante c entre ellos.

Prueba esto:

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

Las primeras salidas de comando:

echo %a:fat=thin% 

que se canaliza en un segundo shell de comandos para la evaluación.

+1

Yo esperaría que este comportamiento, pero también me esperar alguna forma de retrasar la expansión o 'anidar' la expansión. Por cierto, estoy de acuerdo, nada es fácil, ni inmediatamente obvio en DOS. – GKelly

2

Y ... ¿Qué tal esto?

@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?

+0

Ojalá pudiera votar esto 12 veces. – mslissap

1

Recientemente me encontré con los mismos situation..As dicho antes, he usado como el de abajo y trabajó ...

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 

Salida:

\log\process 

Funcionó .. !!

4

Utilice LLAME. Ponga lo siguiente en un archivo por lotes y ejecutarlo:

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 

Como se dijo here, utilizamos el hecho de que:

LLAMADA internal_cmd

...

internal_cmd Ejecuta un comando interno, primero expandiendo cualquier variable en el argumento.

En nuestro caso internal_cmd es inicialmente conjunto a = %% a:% b%^=% c %%%.

Después de la expansión internal_cmd convierte conjunto a =% a: grasa =% delgada.

Por lo tanto, en nuestro caso se ejecuta

establecimiento de llamada a = %% a:% b%^=% c %%%

es equivalente de reproducción:

establecer a =% a: grasa = delgada%.

0

trato de evitar el uso de SETLOCAL enabledelayedexpansion ... ENDLOCAL todas (o casi todas) las veces, porque por lo general quiero establecer o modificar algunas variables y quiero que los nuevos valores que estén disponibles en otras áreas de la secuencia de comandos o después de la finaliza el script por lotes (SETLOCAL | ENDLOCAL se olvidará de las nuevas variables o cambios en las variables en la parte "SETLOCAL" del script. Algunas veces es útil, pero para mí no suele ser así.

Actualmente uso el método descrito por @Zuzel, pero antes de saber sobre ese método, solía usar esto, que es muy similar (pero parece un poco más complicado):

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

script de ejemplo:

@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 

la salida de la ejecución del script:

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

me gusta este método porque se puede llamar a programas externos (o comandos internos) usando variables modificadas y también capturar y procesar la salida del comando (línea por línea).

Pero, el método de Zuzel es más simple y más limpio para la mayoría de las situaciones, incluida la que usted describió.

Nota:

Ambos métodos (y también SETLOCAL enabledelayedexpansion ... ENDLOCAL, por supuesto), sólo funcionan correctamente si se ejecuta desde dentro de un archivo por lotes. Si intenta utilizar cualquiera de estos dos métodos ("llamar" o "para") directamente en una ventana del símbolo del sistema, obtendrá algo diferente de lo que se estaba ejecutando desde un script.

Por ejemplo, ejecutar esto como una secuencia de comandos:

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

la salida de la ejecución del 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") 

Ahora, ejecute los comandos directamente en un símbolo del sistema ventana:

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:\> 

examine las líneas de salida antes y después desde la ventana del símbolo del sistema:

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

Observe que las sustituciones se realizan correctamente, pero también observe que al ejecutar estos comandos directamente en la ventana del símbolo del sistema, agrega un conjunto de "%" (signos de porcentaje) antes y después del valor esperado cada vez la sustitución está hecha. Por lo tanto, hace que sea difícil probar cualquiera de estos métodos directamente en la ventana del símbolo del sistema.

0

:: El uso de Perl en% var% = ~ s/$ vieja/nueva $/

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% 

Salida:

before=The fat cat 
after=The thin cat 
Cuestiones relacionadas