batch-file - array - batch wait for command to finish
¿Cómo funciona "FOR" en el archivo por lotes cmd? (12)
He estado programando en docenas de idiomas durante 20 años, pero nunca pude entender cómo funciona "FOR" en el archivo por lotes del shell de Windows CMD, sin importar cuánto lo intenté. Yo leo
http://www.ss64.com/nt/for.html
y varios otros artículos en Internet, pero aún confunden y no pueden lograr nada.
¿Puede alguien darme una explicación concisa de cómo funciona "FOR" en general?
Para una pregunta un poco más específica, ¿cómo puedo iterar a través de cada ruta en la variable% PATH%? Lo he intentado con
rem showpathenv.bat
for /f "delims=;" %%g in ("%PATH%") do echo %%g
Eso mostraría solo el primer camino, no todos. Por qué ? Qué hice mal ?
Aquí hay una buena guía:
FOR / F - Comando Loop: contra un conjunto de archivos.
FOR / F - Comando Loop: contra los resultados de otro comando.
http://www.ss64.com/nt/for.html
[Toda la guía (comandos de Windows XP):
http://www.ss64.com/nt/index.html
Editar: Lo siento, no vi que el enlace ya estaba en el OP, ya que me pareció como parte del enlace de Amazon.
Esto funciona para mí:
@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
Funciona para mí, pruébalo.
para / f "tokens = * delims =;" % g in (''echo% PATH%'') do echo% g%
Funciona para mí, pruébalo.
for /f "delims=;" %g in (''echo %PATH%'') do echo %g%
La idea de Mark fue buena, pero tal vez olvidó que algunos caminos tienen espacios en ellos. Reemplazando '';'' con '''' '''' ''en su lugar cortaría todas las rutas en cadenas entrecomilladas.
set _path="%PATH:;=" "%"
for %%p in (%_path%) do if not "%%~p"=="" echo %%~p
Así que aquí, tienes tus caminos mostrados.
El comando FOR en cmd tiene una curva de aprendizaje tediosa, especialmente porque las variables reaccionan dentro de las declaraciones () ... puedes asignar cualquier variable, pero no puedes leerla dentro de (), a menos que uses la " setlocal ENABLEDELAYEDEXPANSION ", y por lo tanto también usa las variables con !! ''s en lugar de %%'' s (! _var!)
Actualmente, sigo exclusivamente script con cmd, para el trabajo, tuve que aprender todo esto :)
Ninguna de las respuestas realmente funciona. He logrado encontrar la solución yo mismo. Esto es un poco hackish, pero me solucionó el problema:
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 ! ¡Odio la programación de archivos por lotes!
Actualizado
La solución de Mark es más simple, pero no funcionará con path que contenga espacios en blanco. Esta es una versión poco modificada de la solución de Mark
echo off
setlocal enabledelayedexpansion
set NonBlankPath=%PATH: =#%
set TabbedPath=%NonBlankPath:;= %
for %%g in (%TabbedPath%) do (
set GG=%%g
echo !GG:#= !
)
No pude resistirme a tirar esto por viejo, como este hilo es ... Generalmente, cuando surge la necesidad de iterar a través de cada uno de los archivos en PATH, todo lo que realmente desea hacer es encontrar un archivo en particular ... Si ese es el caso , este one-liner escupirá el primer directorio en el que encuentre tu archivo:
(ejemplo: buscando java.exe)
for %%x in (java.exe) do echo %%~dp$PATH:x
Sé que esto es SUPER viejo ... pero solo por diversión, decidí intentarlo:
@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
Esto no requiere un conteo e irá hasta que termine. Tuve el mismo problema con los espacios, pero pasó a través de toda la variable. La clave para esto es las etiquetas de bucle y la función SHIFT
.
También debe usar los tokens=1,2,...
parte de las opciones que permite el ciclo for
. Esto aquí hará lo que posiblemente quieras:
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")
Este ejemplo procesa los primeros 12 tokens (= directorios de% path%) solamente. Utiliza una enumeración explícita de cada uno de los tokens usados. Tenga en cuenta que los nombres de los tokens distinguen entre mayúsculas y minúsculas:% a es diferente de% A.
Para guardar las rutas con espacios, rodee todo % x con comillas como esta "% i". No lo hice aquí, donde solo hago eco de los tokens.
También podría hacer s.th. Me gusta esto:
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 )
Éste omite tokens 2,4,6 y usa un pequeño atajo (" 7-26
") para nombrar al resto de ellos. Observe cómo% c,% b,% a se procesan en orden inverso esta vez, y cómo ahora "significan" tokens diferentes, en comparación con el primer ejemplo.
Entonces esta seguramente no es la explicación concisa que pediste. Pero tal vez los ejemplos ayudan a aclarar un poco mejor ahora ...
Tiene la idea correcta, pero for /f
está diseñada para trabajar en archivos o comandos de varias líneas, no en cadenas individuales.
En su forma más simple, for
es como Perl''s, o el foreach
todos los demás idiomas. Le pasa una lista de tokens y los itera, llamando al mismo comando cada vez.
for %a in (hello world) do @echo %a
Las extensiones simplemente proporcionan formas automáticas de compilar la lista de tokens. La razón por la que su código actual no genera nada es eso '' ;
''es el símbolo predeterminado de fin de línea (comentario). Pero incluso si cambia eso, tendría que usar %%g, %%h, %%i, ...
para acceder a los tokens individuales, lo que limitará severamente su archivo por lotes.
Lo más cerca que puede llegar a lo que pide es:
set TabbedPath=%PATH:;= %
for %%g in (%TabbedPath%) do echo %%g
Pero eso fallará en las rutas citadas que contienen puntos y comas.
En mi experiencia, for /l
for /r
son buenos para extender los comandos existentes, pero de lo contrario es extremadamente limitado. Puede hacer que sea ligeramente más potente (y confuso) con la expansión de la variable retrasada ( cmd /v:on
), pero en realidad solo sirve para listas de nombres de archivos.
Sugiero usar WSH o PowerShell si necesita realizar manipulación de cadenas. Si está intentando escribir whereis
para Windows, intente where /?
.
FOR
esencialmente itera sobre las "líneas" en el conjunto de datos. En este caso, hay una línea que contiene la ruta. El "delims=;"
simplemente le está diciendo que se separe en punto y coma. Si cambia el cuerpo para que haga un echo %%g,%%h,%%i,%%j,%%k
, verá que está tratando la entrada como una sola línea y dividiéndola en múltiples tokens.
for /f
itera por entrada de línea, por lo que en tu programa solo se generará la primera ruta.
su programa trata% PATH% como entrada de una línea, y delimita por ;
, coloque el primer resultado en %% g, luego genere %% g (primer camino delimitado).