web-dev-qa-db-fra.com

Lot imbriqué pour les boucles

La boucle imbriquée suivante me rend fou (sous Windows 7):

@echo off
SetLocal EnableDelayedExpansion

set TESTDIRS=fast mid slow
set TD=src\test\resources\testsuite

for %%d in (%TESTDIRS%) do (
    set CTD=%TD%\%%d
    echo CTD: !CTD!
        REM Echos the expected path
    echo CTD: %CTD%
        REM Echos nothing -- understandable

    for /R !CTD! %%f in (*.fs) do (echo %%f)
        REM Echos nothing -- why?
    for /R src\test\resources\testsuite\fast %%f in (*.fs) do (echo %%f)
        REM Echos expected files
)

J'ai essayé diverses solutions impliquant la désactivation de DelayedExpansion, des instructions d'appel et ainsi de suite, mais je n'ai jamais réussi à faire fonctionner la boucle interne. Je sais que je pourrais remplacer la boucle interne par un appel de sous-routine, mais il doit y avoir un moyen de la faire fonctionner avec des boucles imbriquées.

20
Malte Schwerhoff

Et si vous utilisiez pushd !CTD! et popd, et laissez FOR /R par défaut pour utiliser le répertoire courant?

11
Ben Voigt

Juste pour donner un exemple d'une boucle imbriquée qui fonctionne:

@echo off
SetLocal

set B=alpha beta gamma
set A=eins zwo

FOR %%b in (%B%) do (
  FOR %%a in (%A% %%b) DO (
    echo %%b -^> %%a
  )
)

La sortie (au moins sur Windows 7) est

alpha -> eins
alpha -> zwo
alpha -> alpha
beta -> eins
beta -> zwo
beta -> beta
gamma -> eins
gamma -> zwo
gamma -> gamma

Cela confirme l'observation de jeb selon laquelle l'expansion variable dans les boucles fonctionne si elles se produisent à l'intérieur des parenthèses (même sans expansion retardée).

23
Malte Schwerhoff

Parce que personne ne l'a mentionné, voici la solution utilisant des sous-routines batch et la commande CALL.

@echo off

set TESTDIRS=fast mid slow
set TD=src\test\resources\testsuite

for %%d in (%TESTDIRS%) do call :process_testdir %%d
goto :eof

:process_testdir
set CTD=%TD%\%1
echo CTD: %CTD%
    REM Echos the expected path

for /R %CTD% %%f in (*.fs) do (echo %%f)
    REM Echos as expected

goto :eof

Je sais que GOTO n'est pas très populaire, mais les fichiers de commandes ont été initialement conçus pour utiliser des étiquettes pour le flux de contrôle. La syntaxe de la structure de contrôle entre parenthèses a été ajoutée plus tard, et cette question est un exemple de la panne. Le problème se prête bien aux sous-programmes batch.

12
Ryan Bemrose

Ce n'est pas évident! C'est l'analyse spéciale de POUR !
Une commande POUR est analysée directement après la phase d'échappement/caractère spécial (pour détecter la parenthèse), mais par conséquent vous ne pouvez pas en utilisant une extension différée ou %% var comme paramètres.

FOR %%a in (%%%%B) do (
  FOR %%a in (1) DO ( <<< this %%a will not replaced with %%B
      echo %%a - shows 1, because %%a is the name of the inner variable
      echo %%B - doesn't work
  )
)

Et cela ne peut pas fonctionner non plus:

set chars=abc
FOR /F "delims=!chars!" %%N in (bla) DO ....  

ne définit pas a, b et c comme délimiteurs, mais !, c , h, a et r à la place.

EDIT: Dans les parenthèses, l'expansion retardée fonctionne comme prévu cependant:

set var=C:\temp
For %%a in (!var!) DO echo %%a

Je suppose que vous devez utiliser une fonction pour résoudre votre problème.

5
jeb

Citer la réponse de Malte Schwerhoff

Si vous ne voulez pas répéter B, vous pouvez simplement ajouter une instruction "if"

@echo off
SetLocal

set B=alpha beta gamma
set A=eins zwo

FOR %%b in (%B%) do (
  FOR %%a in (%A% %%b) DO (
    IF %%b NEQ %%a (
        echo %%b -^> %%a
    )
  )
)

production:

alpha -> eins
alpha -> zwo
beta -> eins
beta -> zwo
gamma -> eins
gamma -> zwo
1
江明哲