2010-12-06 53 views
10

J'écris un script simple pour remplacer du texte dans une variable d'environnement par un autre texte. Le problème que je reçois est le texte substitué ou substitué étant tiré à partir d'autres variablesComment substituer un contenu de variable dans un fichier de commandes Windows

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

fonctionne très bien (sortie est « Le gros chat » et « Le chat mince »

Cependant, si « gras » ou « mince » sont des variables, il ne fonctionne pas

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

Je sais que cela peut être fait comme je l'ai vu dans les blogs, mais je ne le lien sauvé aux blogs.

Toute personne avoir une idée s?

PS. Je cours les manuscrits sur Windows 7

PPS. Je sais que c'est plus facile dans Perl/Python/autre langage de choix, mais je veux juste savoir pourquoi quelque chose qui devrait être facile n'est pas immédiatement évident.

PPPS. J'ai également essayé les scripts avec l'expansion retardée explicitement allumé

SETLOCAL enabledelayedexpansion 

Cela ne fait aucune différence.

Répondre

11

S'il vous plaît essayez ce qui suit:

Copiez et collez le code dans le Bloc-notes et l'enregistrer comme un fichier batch.

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

J'espère que vous êtes convaincu!

2

Le problème avec:

echo %a:%c%=thin% 

est qu'il tente de développer deux variables: a: et =thin avec une constante chaîne c entre eux.

essayer ceci:

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

Les premières sorties de commande:

echo %a:fat=thin% 

qui est canalisé dans une seconde interface de commande pour l'évaluation.

+1

Je me attends à ce comportement, mais je aussi Attendez-vous à un moyen de retarder l'expansion ou d'imbriquer l'expansion. BTW, je suis d'accord, rien n'est facile, ni immédiatement évident dans DOS. – GKelly

2

Et ... Que pensez-vous de cela?

@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

J'aimerais pouvoir voter 12 fois. – mslissap

1

Récemment, je suis tombé sur les mêmes situation..As dit plus tôt, j'ai utilisé comme ci-dessous et travaillé ...

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 

Sortie:

\log\process 

Il a travaillé .. !!

4

Utilisez CALL. Mettez ce qui suit dans un script batch et l'exécuter:

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 

Comme indiqué here, nous utilisons le fait que:

APPEL internal_cmd

...

internal_cmd Exécute une commande interne, en commençant par développer toutes les variables de l'argument.

Dans notre cas internal_cmd est initialement ensemble a = %% a:% b%^=% c %%%.

Après l'expansion internal_cmd devient ensemble a =% a: graisse = mince%.

Ainsi, dans notre cas en cours d'exécution

appel mis a = %% a:% b%^=% c %%%

est équivalent à la course:

définir a =% a: graisse = mince%.

0

J'essaie d'éviter d'utiliser SETLOCAL enabledelayedexpansion ... ENDLOCAL tous (ou presque tous) le temps, parce que généralement je veux définir ou modifier quelques variables et je veux que les nouvelles valeurs soient disponibles dans d'autres régions du script ou après la Le script de lot se termine (SETLOCAL | ENDLOCAL oubliera toutes les nouvelles variables ou les changements de variables dans la partie "SETLOCAL" du script.) Parfois, c'est pratique, mais pour moi, je trouve que ce n'est généralement pas le cas. par @Zuzel, mais avant que je savais sur cette méthode, je l'habitude d'utiliser ceci, qui est très similaire (mais semble un peu plus compliqué):

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

exemple de 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 

la sortie de l'exécution du script:

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

J'aime cette méthode parce que vous pouvez appeler des programmes externes (ou des commandes internes) en utilisant des variables modifiées et également capturer et traiter la sortie de la commande (ligne par ligne). Mais la méthode de Zuzel est plus simple et plus propre pour la plupart des situations, y compris celle que vous avez décrite.

Note:

Ces deux méthodes (et SETLOCAL enabledelayedexpansion ... ENDLOCAL, bien sûr), ne fonctionnera correctement que si elle est exécutée à partir d'un script batch. Si vous essayez d'utiliser l'une de ces deux méthodes ("appel" ou "pour") directement dans une fenêtre d'invite de commande, vous obtiendrez quelque chose de différent de ce que la sortie exécutait à partir d'un script.

Par exemple, exécutez comme un 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%") 

la sortie de l'exécution du 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") 

Maintenant, exécutez les commandes directement dans une fenêtre d'invite:

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 les lignes de sortie avant et après à partir de la fenêtre d'invite de commande:Remarquez que les substitutions sont effectuées correctement, mais notez également qu'en exécutant ces commandes directement dans la fenêtre d'invite de commande, il ajoute un ensemble de «%» (signes de pourcentage) avant et après la valeur attendue à chaque fois. la substitution est faite. Ainsi, il est difficile de tester l'une de ces méthodes directement dans la fenêtre d'invite de commande.

0

:: Utilisez Perl% var% = ~ s/$ ancienne/$ nouvelle/

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% 

Sortie:

before=The fat cat 
after=The thin cat