it-swarm.com.ru

Как работает "FOR" в командном файле cmd?

Я программирую на десятках языков в течение 20 лет, но я никогда не мог понять, как «ЗА» работать в командном файле оболочки Windows cmd, как бы я ни старался. Я читаю 

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

и несколько других статей в интернете, но все еще смущают и ничего не могут сделать.

Кто-нибудь может дать мне краткое объяснение того, как «ЗА» работает в целом?

Для немного более конкретного вопроса, как я могу перебрать каждый путь в переменной% PATH%? Я пытался с 

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

Это показало бы только первый путь, а не все. Зачем ? Что я делаю не так?

23
Sake

Ни один из ответов на самом деле не работает. Я сумел найти решение сам .. Это немного глупо, но это решает проблему для меня:

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

Ой ! Я ненавижу программирование пакетных файлов!

Обновлено

Решение Марка проще, но оно не будет работать с путями, содержащими пробелы. Это немного модифицированная версия решения Марка

echo off
setlocal enabledelayedexpansion
set NonBlankPath=%PATH: =#%
set TabbedPath=%NonBlankPath:;= %
for %%g in (%TabbedPath%) do (
  set GG=%%g
  echo !GG:#= !
)
12
Sake

Идея Марка была хороша, но, возможно, забыл, что на некоторых путях есть пробелы. Замена ';' вместо "" "все пути будут разделены на строки в кавычках.

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

Итак, у вас есть ваши пути отображаются.

Команда FOR в cmd имеет утомительную кривую обучения, в частности потому, что как переменные реагируют в выражениях () ... вы можете назначать любые переменные, но вы не можете затем читать обратно в (), если вы не используете " setlocal ENABLEDELAYEDEXPANSION ", и поэтому также используйте переменные с !! вместо %% (! _var!)

Я на данный момент исключительно скрипт с cmd, для работы пришлось все это выучить :)

5
Jay

Не смог устоять перед тем, чтобы выбросить это, старый, как этот поток ... Обычно, когда возникает необходимость перебирать каждый из файлов в PATH, все, что вы действительно хотите сделать, это найти конкретный файл ... Если это так этот однострочный выложит первый каталог, в котором найдет ваш файл:

(например: ищу Java.exe)

for %%x in (Java.exe) do echo %%~dp$PATH:x
4
Tikonu

Вы правильно поняли, но 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 /?.

4
Mark

Я знаю, что это СУПЕР старое ... но просто для удовольствия я решил попробовать это:

@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.

3
iesou

Вы должны дополнительно использовать часть параметров 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.

Чтобы сохранить пути с пробелами, окружитеall% x кавычками, подобными этой "% i". Я не делал это здесь, где я только повторяю жетоны.

Вы также можете сделать s.th. как это:

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 обрабатываются в обратном порядке на этот раз, и как они теперь «означают» разные токены по сравнению с первым примером.

Так что это, конечно, не краткое объяснение, которое вы просили. Но, возможно, примеры помогут прояснить немного лучше сейчас ...

2
Kurt Pfeifle

for /f выполняет итерацию для каждого ввода строки, поэтому в вашей программе будет выводиться только первый путь.

ваша программа обрабатывает% PATH% как однострочный ввод и уменьшает его с помощью ;, сначала помещает результат в %% g, затем выводит %% g (первый путь с разделителями).

2
Francis

FOR, по сути, выполняет итерацию по «строкам» в наборе данных. В этом случае есть одна строка, которая содержит путь. "delims=;" просто указывает на разделение на точки с запятой. Если вы измените тело на echo %%g,%%h,%%i,%%j,%%k, вы увидите, что оно обрабатывает ввод как одну строку и разбивает его на несколько токенов.

2
D.Shawley

Это работает для меня: 

@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
2
Cheeso

Вот хорошее руководство:

FOR/F - Loop команда: против набора файлов.

FOR/F - Циклическая команда: против результатов другой команды.

FOR - Loop команда: все опции Файлы, Каталог, Список.

[Полное руководство (команды Windows XP):

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

Edit: Извините, не увидел, что ссылка уже была в OP, так как она показалась мне как часть ссылки Amazon.

1
TFM

Это работает для меня, попробуйте.

for /f "delims=;" %g in ('echo %PATH%') do echo %g%
0
BerY