Fichier de commandes. Variable dans variable

2

Comment utiliser des variables dans des variables? Ce code:

set newvar=%var%var2%%

ne fonctionne pas. Alors que faire? Je ne peux pas écrire mon programme sans celui-ci.

utilisateur339962
la source
Je pense que je comprends ce que vous voulez et si les réponses ci-dessous l’interprètent mal: si je ne me trompe pas, vous voulez que var2 contienne une valeur telle que A , vous voulez donc que newvar soit défini sur le contenu de varA . La seule façon que j'ai trouvée de faire une analyse double de CMD est d'utiliser echo set newvar=%%var%var2%>temp.cmd, alors .\temp.cmd. Un peu lourd, mais ça marche.
AFH
Désolé @mihi - Je pense que votre réponse fait la même chose, mais je n'ai jamais rencontré usebackq auparavant et je ne peux pas utiliser correctement la syntaxe. Je regarderai encore quand je serai moins fatigué.
AFH

Réponses:

1

Je suis d'accord avec AFH; vous devez obtenir que CMD «double analyse» la setdéclaration. Mais j'ai trouvé un moyen de le faire sans faire appel à un fichier de commandes temporaire (ou en examinant chaque variable pour trouver celle que vous voulez). Il utilise un sous-programme et une astuce appelée expansion variable différée. Activer l'expansion retardée en ajoutant

setlocal enabledelayedexpansion

quelque part vers le début de votre fichier de commandes. Le but de l’expansion retardée des variables est quelque peu compliqué - voir SET /?et SETLOCAL /?pour plus d’informations - mais il est important de savoir que cela vous permet de référencer des variables en plus de .!variable_name!%variable_name%

Alors on y va:

@echo off
setlocal enabledelayedexpansion
set var1=red
set var2=orange
set var3=yellow
set A=2
call :kludge var%A%
echo Newvar is %newvar%.
goto :eof

:kludge
set newvar=!%1!
exit /b

Lorsque nous sautons à :kludge, l'instruction est d'abord transformée en set newvar=!var2! (car  %1, le premier argument du sous-programme, est var2), puis set newvar=orange(comme si l'instruction avait été set newvar=%var2%). Alors newvarse prépare à orange.

BTW, goto :eofet exit /bsont interchangeables. Si elles sont appelées depuis un sous-programme (c’est-à-dire à un endroit où vous avez une calldéclaration), elles renverront l’appelant. Sinon, ils agissent comme un saut vers la fin du fichier de commandes, entraînant la fin du travail par lots sans supprimer la commande parent, interactive, d'invite de commande.

Scott
la source
Il n'y a rien de mal à propos de l'expansion retardée. C’est une fonctionnalité importante de cmd.exe, et j’estime qu’il s’agit d’un composant essentiel de la quasi-totalité de mes scripts batch intermédiaires ou avancés. Il n'y a pas besoin de votre :kludgeroutine. Vous pouvez simplement utiliser set "newvar=!var%A%!", comme je l'ai démontré dans ma réponse .
Dbenham
@dbenham: Vous avez pris les mots de ma bouche - ma réponse est un kludge car il nécessite un sous-programme pour exécuter une seule déclaration.
Scott
1
Je devrais tempérer un peu mon dernier commentaire. L'expansion retardée n'est ni plus ni moins kludgy que tout autre aspect de cmd.exe. Certains pourraient prétendre que le processeur de commande complet n'est qu'un gros kludge, et à certains égards, je serais d'accord ;-)
dbenham le
4

Une méthode relativement lente. La commande CALL fournit un niveau supplémentaire d’expansion des variables. Les pourcentages autour du nom de la variable externe sont doublés pour retarder l'expansion après que la variable interne ait été développée.

@echo off
setlocal
set "var1=value"
set "var2=1"
call set "newvar=%%var%var2%%%"

Une méthode bien meilleure consiste à utiliser une expansion retardée. Il doit d'abord être activé avec SETLOCAL ENABLEDELAYEDEXPANSION. La variable dans les pourcentages est développée lorsque la ligne est analysée. La variable entre les points d'exclamation est étendue après l'analyse, juste avant que la ligne soit exécutée.

@echo off
setlocal enableDelayedExpansion
set "var1=value"
set "var2=1"
set "newvar=!var%var2%!"
Dbenham
la source
Hmm. Je suis perplexe. Selon les horodatages de Super User, vous avez posté ceci avant que je poste ma réponse - mais je ne me souviens pas de l'avoir vue auparavant.
Scott
@Scott - Ma réponse a en effet été présente depuis le début, environ 12 heures avant que la vôtre ne soit affichée.
Dbenham
Eh bien, j'ai peut-être eu un problème avec mon navigateur ou ma connexion Internet. Le fait est que je n'ai pas volé votre réponse (très élégante) - si je l'avais vue, je n'aurais pas posté la mienne - et je vous ai fait voter. BTW, j'ai essayé set newvar=%var!A!%- si proche, mais pas de cigare!
Scott
1
@Scott - Pas de soucis :-) La logique derrière l' %var!A!%échec et le !var%A%!fonctionnement est assez simple une fois que vous connaissez l'ordre des différentes phases d'expansion.
Dbenham
1

Généralement, j'essayerais d'éviter des scénarios comme celui-ci. Bien que ce soit possible, il est loin d’être performant et difficile à lire non plus - vous devez en principe analyser le résultat de la setcommande.

set index=9
set var9=Goal

echo %var9%
for /F "usebackq tokens=1* delims==" %I in (`set`) do if "%I" == "var%index%" set result=%J
echo %result%
Mihi
la source
Aie. Ce type de travail fonctionne, mais il pourrait échouer si la recherche de VAR1 et VAR10 existe également. Il pourrait être grandement optimisé et rendu encore plus infaillible. Mais il existe des méthodes bien meilleures (et beaucoup plus simples).
Dbenham
@dbenham alors que je dois admettre que les autres solutions sont plus faciles (mais ne fonctionnaient probablement pas sous NT4, qui était le dernier système d'exploitation pour lequel j'avais plus de contacts avec la programmation par lots - plus tard, j'ai toujours essayé d'utiliser vbs ou PoSH), mais je ne le fais pas. Voyez pourquoi VAR10 peut poser problème - les delimsfractionnements% I% en avant = et% J% en après =, et = ne peuvent pas être dans les noms de variable AFAIK.
Mihi
Désolé mon mauvais. Vous avez tout à fait raison. J'étais confus avec l'optimisation de l'utilisation in (set var%index%)que j'avais en train de fouiller dans ma tête. La seule situation dans laquelle votre solution ne fonctionnerait pas serait si la valeur commençait par =. Je ne suis pas sûr de savoir quand l'expansion retardée a été introduite, mais je soupçonne que le CALL avec des pourcentages doublés fonctionnerait dans NT4.
Dbenham