Je programme dans des dizaines de langues depuis 20 ans, mais je ne pouvais jamais comprendre comment "POUR" fonctionnait dans un fichier de commandes Windows cmd Shell, peu importe les efforts que j'avais déployés. J'ai lu
http://www.ss64.com/nt/for.html
et plusieurs autres articles sur Internet mais qui restent confus et ne peuvent rien accomplir.
Quelqu'un peut-il me donner une explication concise sur la manière dont "POUR" fonctionne en général?
Pour une question un peu plus spécifique, comment puis-je parcourir chaque chemin dans la variable% PATH%? J'ai essayé avec
rem showpathenv.bat
for /f "delims=;" %%g in ("%PATH%") do echo %%g
Cela ne montrerait que le premier chemin, pas tous. Pourquoi ? Ce que je fais mal ?
Aucune des réponses ne fonctionne réellement. J'ai réussi à trouver la solution moi-même ... C'est un peu bizarre, mais cela résout le problème pour moi:
echo off
setlocal enableextensions
setlocal enabledelayedexpansion
set MAX_TRIES=100
set P=%PATH%
for /L %%a in (1, 1, %MAX_TRIES%) do (
for /F "delims=;" %%g in ("!P!") do (
echo %%g
set P=!P:%%g;=!
if "!P!" == "%%g" goto :eof
)
)
Oh! Je déteste la programmation par lots !!
Mis à jour
La solution de Mark est plus simple, mais elle ne fonctionnera pas avec les chemins contenant des espaces. Ceci est une version légèrement modifiée de la solution de Mark
echo off
setlocal enabledelayedexpansion
set NonBlankPath=%PATH: =#%
set TabbedPath=%NonBlankPath:;= %
for %%g in (%TabbedPath%) do (
set GG=%%g
echo !GG:#= !
)
L'idée de Mark était bonne, mais peut-être oublié que certains chemins ont des espaces. Remplacement de ';' avec '""' découperait tous les chemins en chaînes entre guillemets.
set _path="%PATH:;=" "%"
for %%p in (%_path%) do if not "%%~p"=="" echo %%~p
Donc, ici, vous avez vos chemins affichés.
La commande FOR dans cmd a une courbe d’apprentissage fastidieuse, notamment parce que la réaction des variables dans les instructions de () ... setlocal ENABLEDELAYEDEXPANSION ", et donc aussi utiliser les variables avec !! au lieu de %% (! _var!)
Je suis actuellement exclusivement en script avec cmd, pour le travail, j'ai dû apprendre tout cela :)
Je ne pouvais pas m'empêcher de jeter ça là-bas, aussi vieux que soit ce fil de discussion ... Habituellement, lorsque vous avez besoin de parcourir chacun des fichiers de PATH, tout ce que vous voulez vraiment faire est de trouver un fichier particulier ... Si c'est le cas , ce one-liner crache le premier répertoire dans lequel il trouve votre fichier:
(ex: recherche de Java.exe)
for %%x in (Java.exe) do echo %%~dp$PATH:x
Vous avez la bonne idée, mais for /f
est conçu pour fonctionner sur des fichiers ou des commandes multilignes, et non sur des chaînes individuelles.
Dans sa forme la plus simple, for
est semblable à for
de Perl, ou à foreach
de toutes les autres langues. Vous lui transmettez une liste de jetons, qui itère sur eux en appelant la même commande à chaque fois.
for %a in (hello world) do @echo %a
Les extensions fournissent simplement des moyens automatiques de construction de la liste des jetons. La raison pour laquelle votre code actuel n’affiche rien est que ";
" est le symbole de fin de ligne (commentaire) par défaut. Mais même si vous modifiez cela, vous devrez utiliser %%g, %%h, %%i, ...
pour accéder aux jetons individuels, ce qui limitera considérablement votre fichier de commandes.
Le plus proche que vous pouvez obtenir à ce que vous demandez est:
set TabbedPath=%PATH:;= %
for %%g in (%TabbedPath%) do echo %%g
Mais cela échouera pour les chemins cités contenant des points-virgules.
D'après mon expérience, for /l
et for /r
sont utiles pour l'extension de commandes existantes, mais sinon, for
est extrêmement limité. Vous pouvez le rendre légèrement plus puissant (et déroutant) avec l’extension retardée des variables (cmd /v:on
), mais c’est vraiment bon pour les listes de noms de fichiers.
Je suggérerais d'utiliser WSH ou PowerShell si vous devez effectuer une manipulation de chaîne. Si vous essayez d'écrire whereis
pour Windows, essayez where /?
.
Je sais que c'est très vieux ... mais juste pour m'amuser, j'ai décidé de tenter le coup:
@Echo OFF
setlocal
set testpath=%path: =#%
FOR /F "tokens=* delims=;" %%P in ("%testpath%") do call :loop %%P
:loop
if '%1'=='' goto endloop
set testpath=%1
set testpath=%testpath:#= %
echo %testpath%
SHIFT
goto :loop
:endloop
pause
endlocal
exit
Cela ne nécessite pas de comptage et ira jusqu'à ce qu'il se termine. J'ai eu le même problème avec les espaces mais cela a traversé la variable entière. La clé est les étiquettes de boucle et la fonction SHIFT
.
Vous devez également utiliser la partie tokens=1,2,...
des options autorisées par la boucle for
. Cette ici fera ce que vous voulez éventuellement:
for /f "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims=;" %a in ("%PATH%") ^
do ( ^
echo. %b ^
& echo. %a ^
& echo. %c ^
& echo. %d ^
& echo. %e ^
& echo. %f ^
& echo. %g ^
& echo. %h ^
& echo. %i ^
& echo. %j ^
& echo. %k ^
& echo. ^
& echo. ...and now for some more... ^
& echo. ^
& echo. %a ^| %b ___ %c ... %d ^
& dir "%e" ^
& cd "%f" ^
& dir /tw "%g" ^
& echo. "%h %i %j %k" ^
& cacls "%f")
Cet exemple traite uniquement les 12 premiers jetons (= répertoires de% path%). Il utilise une énumération explicite de chacun des jetons utilisés. Notez que les noms de jeton sont sensibles à la casse:% a est différent de% A.
Pour sauvegarder les chemins comportant des espaces, entoureztout% x avec des guillemets comme celui-ci "% i". Je ne l'ai pas fait ici où je ne fais que faire écho aux jetons.
Vous pouvez aussi faire quelque chose comme ça:
for /f "tokens=1,3,5,7-26* delims=;" %a in ("%PATH%") ^
do ( ^
echo. %c ^
& echo. %b ^
& echo. %a ^
& echo. %d ^
& echo. %e ^
& echo. %f ^
& echo. %g ^
& echo. %h ^
& echo. %i ^
& echo. %j ^
& echo. %k )
Celui-ci saute les jetons 2,4,6 et utilise un petit raccourci ("7-26
") pour nommer les autres. Notez comment% c,% b,% a sont traités en ordre inverse cette fois-ci et comment ils "signifient" maintenant différents jetons par rapport au premier exemple.
Donc, ce n'est sûrement pas l'explication concise que vous avez demandée. Mais peut-être que les exemples aident à clarifier un peu mieux maintenant ...
for /f
itère une entrée par ligne, ainsi votre programme ne sortira que le premier chemin.
votre programme traite% PATH% comme une entrée d'une ligne et supprime par ;
, met le premier résultat dans %% g, puis affiche %% g (le premier chemin supprimé).
FOR
parcourt essentiellement les "lignes" de l'ensemble de données. Dans ce cas, une ligne contient le chemin. Le "delims=;"
indique simplement qu'il faut séparer les points-virgules. Si vous modifiez le corps en echo %%g,%%h,%%i,%%j,%%k
, vous verrez qu'il traite l'entrée comme une seule ligne et la divise en plusieurs jetons.
Cela fonctionne pour moi:
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
@REM insure path is terminated with a ;
set tpath=%path%;
echo.
:again
@REM This FOR statement grabs the first element in the path
FOR /F "delims=;" %%I IN ("%TPATH%") DO (
echo %%I
@REM remove the current element of the path
set TPATH=!TPATH:%%I;=!
)
@REM loop back if there is more to do.
IF DEFINED TPATH GOTO :again
ENDLOCAL
Voici un bon guide:
FOR/F - Commande de boucle: contre un ensemble de fichiers.
FOR/F - Commande de boucle: contre les résultats d'une autre commande.
Commande FOR - Loop: toutes les options Fichiers, Répertoire, Liste.
[Le guide complet (commandes Windows XP):
http://www.ss64.com/nt/index.html
Edit: Désolé, je n'ai pas vu que le lien était déjà dans l'OP, car il me semblait faire partie du lien Amazon.
Cela fonctionne pour moi, essayez-le.
for /f "delims=;" %g in ('echo %PATH%') do echo %g%