web-dev-qa-db-fra.com

fichiers batch Windows: définition de la variable dans la boucle

J'ai un certain nombre de fichiers avec le même schéma de dénomination. À titre d'exemple, quatre fichiers sont appelés "num_001_001.txt", "num_002_001.txt", "num_002_002.txt", "num_002_003.txt"

Le premier ensemble de nombres représente le "package" dont il est issu, et le deuxième ensemble de nombres est simplement utilisé pour les distinguer les uns des autres. Donc, dans cet exemple, nous avons un fichier dans le package 001 et trois fichiers dans le package 002.

J'écris une commande batch Windows Vista pour prendre tous les fichiers et les déplacer dans leurs propres répertoires, où chaque répertoire représente un package différent. Je veux donc déplacer tous les fichiers du package 001 dans le répertoire "001" et tous pour 002 dans le répertoire "002"

J'ai réussi à écrire un script qui itérera sur tous les fichiers txt et les fera écho. J'ai également écrit un script qui déplacera un fichier vers un autre emplacement, ainsi que la création du répertoire s'il n'existe pas.

Maintenant, je pense que j'aurai besoin d'utiliser des sous-chaînes, j'ai donc utilisé la syntaxe% var: ~ start, end% pour les obtenir. Comme test, j'ai écrit ceci pour vérifier que je peux réellement extraire la sous-chaîne et créer un répertoire sous condition

 @ echo off 
 set temp = num_001_001.txt 
 PAS SI existe% temp: ~ 0,7%\
 mkdir% temp: ~ 0,7% 

Et il fonctionne. Génial.
Alors j'ai ajouté la boucle for.

@echo off 
 FOR/R %% X IN (* .txt) DO (
 set temp = %% ~ nX 
 echo directory% temp: ~ 0,7% 
) 

Mais voici ma sortie:

 répertoire num_002 
 répertoire num_002 
 répertoire num_002 
 répertoire num_002 

Qu'est-ce qui ne va pas? Vista ne prend-il pas en charge la réaffectation des variables à chaque itération? Les quatre fichiers se trouvent dans mon répertoire et l'un d'eux devrait créer num_001. J'ai mis dans différents fichiers avec 003 004 005 et tout cela était le nom du dernier paquet. Je suppose que quelque chose ne va pas avec la façon dont je règle les choses.

J'ai différentes solutions pour faire le travail, mais je ne comprends pas pourquoi un concept aussi simple ne fonctionnerait pas.

25
That Umbrella Guy

Votre problème est que la variable est remplacée lorsque le processeur par lots lit la commande for, avant son exécution.

Essaye ça:

SET temp=Hello, world!
CALL yourbatchfile.bat

Et vous verrez Bonjour imprimé 5 fois.

La solution est une expansion retardée; vous devez d'abord l'activer, puis utiliser !temp! au lieu de %temp%:

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /R %%X IN (*.txt) DO (
  set temp=%%~nX
  echo directory !temp:~0,7!
)

Voir ici pour plus de détails.

54
configurator

Une autre solution consiste à déplacer le corps de la boucle for vers un sous-programme et call celui-ci.

@echo off
FOR /R %%X IN (*.txt) DO call :body %%X
goto :eof

:body
set temp=%~n1
echo directory %temp:~0,7%
goto :eof

Pourquoi faire ceci? L'une des raisons est que le processeur de commandes Windows est avide de parenthèses, et les résultats peuvent être surprenants. Je rencontre généralement cela lors du déréférencement de variables qui contiennent C:\Program Files (x86).

Si le processeur de commandes Windows était moins gourmand, le code suivant afficherait One (1)Two (2) ou rien du tout:

@echo off
if "%1" == "yes" (
   echo 1 (One)
   echo 2 (Two)
)

Mais ce n'est pas ce qu'il fait. Soit il imprime 1 (One2 (Two), qui manque un ), Soit il imprime 2 (Two). Le processeur de commandes interprète le ) Après One comme la fin du corps de l'instruction if, traite le second echo comme s'il était en dehors du if, et ignore la dernière ).

14
bk1e

Je ne sais pas si cela est officiellement documenté, mais vous pouvez simuler une expansion retardée à l'aide de l'instruction call:

@echo off
FOR /R %%X IN (*.txt) DO (
  set temp=%%~nX
  call echo directory %%temp:~0,7%%
)

Le doublement des signes de pourcentage reporte la substitution de variable à la deuxième évaluation. Cependant, une expansion retardée est beaucoup plus simple.

4
bk1e