可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I've been programming in dozens of languages for 20 years but I could never understand how "FOR" work in windows cmd shell batch file, no matter how hard I tried. I read
http://www.amazon.com/Windows-Administration-Command-Line-Vista/dp/0470046163/ref=sr_1_1?ie=UTF8&s=books&qid=1241362727&sr=8-1
http://www.ss64.com/nt/for.html
and several other articles on the internet but still confuse and cannot accomplish anything.
Can anybody give me a concise explaination on how "FOR" works in general ?
For a little more specific question, how can I iterate through each path in %PATH% variable ?
I've tried with
rem showpathenv.bat
for /f "delims=;" %%g in ("%PATH%") do echo %%g
That'd show only the first path, not all of them. Why ? What I do wrong ?
回答1:
None of the answers actually work. I've managed to find the solution myself.
This is a bit hackish, but it solve the problem for me:
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 ! I hate batch file programming !!
Updated
Mark's solution is simpler but it won't work with path containing whitespace. This is a little-modified version of Mark's solution
echo off
setlocal enabledelayedexpansion
set NonBlankPath=%PATH: =#%
set TabbedPath=%NonBlankPath:;= %
for %%g in (%TabbedPath%) do (
set GG=%%g
echo !GG:#= !
)
回答2:
Mark's idea was good, but maybe forgot some path have spaces in them. Replacing ';' with '" "' instead would cut all paths into quoted strings.
set _path="%PATH:;=" "%"
for %%p in (%_path%) do if not "%%~p"=="" echo %%~p
So here, you have your paths displayed.
FOR command in cmd has a tedious learning curve, notably because how variables react within ()'s statements... you can assign any variables, but you can't read then back within the ()'s, unless you use the "setlocal ENABLEDELAYEDEXPANSION" statement, and therefore also use the variables with !!'s instead of %%'s (!_var!)
I currently exclusively script with cmd, for work, had to learn all this :)
回答3:
You've got the right idea, but for /f
is designed to work on multi-line files or commands, not individual strings.
In its simplest form, for
is like Perl's for
, or every other language's foreach
. You pass it a list of tokens, and it iterates over them, calling the same command each time.
for %a in (hello world) do @echo %a
The extensions merely provide automatic ways of building the list of tokens. The reason your current code is coming up with nothing is that ';
' is the default end of line (comment) symbol. But even if you change that, you'd have to use %%g, %%h, %%i, ...
to access the individual tokens, which will severely limit your batch file.
The closest you can get to what you ask for is:
set TabbedPath=%PATH:;= %
for %%g in (%TabbedPath%) do echo %%g
But that will fail for quoted paths that contain semicolons.
In my experience, for /l
and for /r
are good for extending existing commands, but otherwise for
is extremely limited. You can make it slightly more powerful (and confusing) with delayed variable expansion (cmd /v:on
), but it's really only good for lists of filenames.
I'd suggest using WSH or PowerShell if you need to perform string manipulation. If you're trying to write whereis
for Windows, try where /?
.
回答4:
Couldn't resist throwing this out there, old as this thread is... Usually when the need arises to iterate through each of the files in PATH, all you really want to do is find a particular file... If that's the case, this one-liner will spit out the first directory it finds your file in:
(ex: looking for java.exe)
for %%x in (java.exe) do echo %%~dp$PATH:x
回答5:
I know this is SUPER old... but just for fun I decided to give this a try:
@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
This doesn't require a count and will go until it finishes. I had the same problem with spaces but it made it through the entire variable. The key to this is the loop labels and the SHIFT
function.
回答6:
for /f
iterates per line input, so in your program will only output first path.
your program treats %PATH% as one-line input, and deliminate by ;
, put first result to %%g, then output %%g (first deliminated path).
回答7:
FOR
is essentially iterating over the "lines" in the data set. In this case, there is one line that contains the path. The "delims=;"
is just telling it to separate on semi-colons. If you change the body to echo %%g,%%h,%%i,%%j,%%k
you'll see that it is treating the input as a single line and breaking it into multiple tokens.
回答8:
This works for me:
@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
回答9:
You have to additionally use the tokens=1,2,...
part of the options that the for
loop allows. This here will do what you possibly want:
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")
This example processes the first 12 tokens (=directories from %path%) only. It uses explicit enumeration of each of the used tokens. Note, that the token names are case sensitive: %a is different from %A.
To be save for paths with spaces, surround all %x with quotes like this "%i". I didn't do it here where I'm only echoing the tokens.
You could also do s.th. like this:
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 )
This one skips tokens 2,4,6 and uses a little shortcut ("7-26
") to name the rest of them. Note how %c, %b, %a are processed in reverse order this time, and how they now 'mean' different tokens, compared to the first example.
So this surely isn't the concise explanation you asked for. But maybe the examples help to clarify a little better now...
回答10:
Here is a good guide:
FOR /F - Loop command: against a set of files.
FOR /F - Loop command: against the results of another command.
FOR - Loop command: all options Files, Directory, List.
[The whole guide (Windows XP commands):
http://www.ss64.com/nt/index.html
Edit: Sorry, didn't see that the link was already in the OP, as it appeared to me as a part of the Amazon link.
回答11:
It works for me, try it.
for /f "delims=;" %g in ('echo %PATH%') do echo %g%
回答12:
It works for me, try it.
for /f "tokens=* delims=;" %g in ('echo %PATH%') do echo %g%