23

我已经用几十种语言编程了 20 年,但无论我多么努力,我都无法理解“FOR”在 windows cmd shell 批处理文件中是如何工作的。我读

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

以及互联网上的其他几篇文章,但仍然感到困惑并且无法完成任何事情。

谁能给我一个关于“FOR”一般如何工作的简明解释?

对于更具体的问题,如何遍历 %PATH% 变量中的每个路径?我试过了

rem showpathenv.bat
for /f "delims=;" %%g in ("%PATH%") do echo %%g

那只会显示第一条路径,而不是全部。为什么 ?我做错了什么?

4

12 回答 12

12

没有一个答案真的有效。我自己设法找到了解决方案。这有点骇人听闻,但它为我解决了问题:

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
  )
)

哦 !我讨厌批处理文件编程!

更新

Mark 的解决方案更简单,但不适用于包含空格的路径。这是马克解决方案的一个小修改版本

echo off
setlocal enabledelayedexpansion
set NonBlankPath=%PATH: =#%
set TabbedPath=%NonBlankPath:;= %
for %%g in (%TabbedPath%) do (
  set GG=%%g
  echo !GG:#= !
)
于 2009-05-04T02:22:07.810 回答
5

马克的想法很好,但可能忘记了一些路径中有空格。替换';' 使用 '" "' 代替会将所有路径切割成带引号的字符串。

set _path="%PATH:;=" "%"
for %%p in (%_path%) do if not "%%~p"=="" echo %%~p

所以在这里,你有你的路径显示。

cmd 中的 FOR 命令有一条乏味的学习曲线,特别是因为变量在 () 的语句中如何反应……你可以分配任何变量,但你不能在 () 中读回,除非你使用 " setlocal ENABLEDELAYEDEXPANSION" 语句,因此也使用带有 !!'s 的变量而不是 %%'s (!_var!)

我目前专门用 cmd 编写脚本,为了工作,必须学习所有这些:)

于 2009-08-18T12:58:36.230 回答
4

您有正确的想法,但for /f设计用于处理多行文件或命令,而不是单个字符串。

在其最简单的形式中,for就像 Perl 的for或其他所有语言的foreach. 你向它传递一个令牌列表,它会遍历它们,每次都调用相同的命令。

for %a in (hello world) do @echo %a

扩展仅提供构建令牌列表的自动方式。您当前的代码一无所获的原因是 ' ;' 是默认的行尾(注释)符号。但即使你改变它,你也必须使用%%g, %%h, %%i, ...来访问单个令牌,这将严重限制你的批处理文件。

最接近您要求的是:

set TabbedPath=%PATH:;= %
for %%g in (%TabbedPath%) do echo %%g

但是对于包含分号的引用路径,这将失败。

根据我的经验,for /l对于for /r扩展现有命令很有用,但在其他for方面非常有限。您可以通过延迟变量扩展 ( ) 使其功能更强大(并且令人困惑)cmd /v:on,但它实际上只适用于文件名列表。

如果您需要执行字符串操作,我建议您使用 WSH 或 PowerShell。如果您尝试whereis为 Windows 编写代码,请尝试where /?.

于 2009-05-03T15:28:57.460 回答
4

忍不住把它扔在那里,因为这个线程很旧......通常当需要遍历 PATH 中的每个文件时,你真正想要做的就是找到一个特定的文件......如果是这样的话,这个单线将吐出它找到你的文件的第一个目录:

(例如:寻找 java.exe)

for %%x in (java.exe) do echo %%~dp$PATH:x
于 2013-02-24T17:48:34.403 回答
3

我知道这是超级老...但只是为了好玩我决定试一试:

@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

这不需要计数,并且会一直持续到完成。我对空格也有同样的问题,但它通过了整个变量。关键是循环标签和SHIFT函数。

于 2012-05-01T16:13:35.780 回答
2

for /f每行输入迭代,所以在你的程序中只会输出第一个路径。

您的程序将 %PATH% 视为单行输入,并用 分隔;,将第一个结果放入 %%g,然后输出 %%g(第一个分隔路径)。

于 2009-05-03T15:23:11.560 回答
2

FOR本质上是迭代数据集中的“线”。在这种情况下,只有一行包含路径。这"delims=;"只是告诉它用分号分隔。如果将正文更改为,echo %%g,%%h,%%i,%%j,%%k您会看到它将输入视为单行并将其分解为多个标记。

于 2009-05-03T15:31:20.450 回答
2

这对我有用:

@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
于 2009-09-15T19:34:04.957 回答
2

您必须另外使用循环允许的tokens=1,2,...部分选项。for这将做你可能想要的:

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")

此示例仅处理前 12 个标记(=来自 %path% 的目录)。它使用每个使用的标记的显式枚举。请注意,令牌名称区分大小写:%a 与 %A 不同。

为了保存带有空格的路径,请将所有%x 用引号括起来,例如“%i”。我没有在这里做,我只是在呼应令牌。

你也可以做某事。像这样:

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 )

这个跳过标记 2,4,6 并使用一个小快捷方式 (" 7-26") 来命名其余的标记。请注意,与第一个示例相比,这次 %c、%b、%a 是如何以相反的顺序处理的,以及它们现在如何“表示”不同的标记。

所以这肯定不是你要求的简明解释。但也许这些例子现在有助于澄清一点......

于 2010-08-07T22:09:05.420 回答
1

这是一个很好的指南:

FOR /F - 循环命令:针对一组文件。

FOR /F - 循环命令:针对另一个命令的结果。

FOR - 循环命令:所有选项文件、目录、列表。

[整个指南(Windows XP 命令):

http://www.ss64.com/nt/index.html

编辑:抱歉,没有看到该链接已经在 OP 中,因为它在我看来是亚马逊链接的一部分。

于 2009-05-03T15:39:56.170 回答
0

它对我有用,试试吧。

for /f "delims=;" %g in ('echo %PATH%') do echo %g%
于 2015-09-11T14:16:44.653 回答
-2

它对我有用,试试吧。

for /f "tokens=* delims=;" %g in ('echo %PATH%') 回显 %g%

于 2017-04-06T16:40:55.587 回答