Как «FOR» работает в командном файле cmd?
-
03-07-2019 - |
Вопрос
Я программировал на десятках языков в течение 20 лет, но никогда не мог понять, как работает «FOR» в командном файле оболочки Windows cmd, как бы я ни старался.Я читаю
http://www.ss64.com/nt/for.html
и несколько других статей в Интернете, но все равно сбивает с толку и ничего не может сделать.
Может ли кто-нибудь дать мне краткое объяснение того, как вообще работает «ЗА»?
Немного более конкретный вопрос: как я могу перебирать каждый путь в переменной %PATH%?Я пробовал с
rem showpathenv.bat
for /f "delims=;" %%g in ("%PATH%") do echo %%g
Это покажет только первый путь, а не все.Почему ?Что я делаю не так?
Решение
Ни один из ответов на самом деле не работает.Мне удалось найти решение самостоятельно.Это немного хакерски, но для меня это решает проблему:
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:#= !
)
Другие советы
Идея Марка была хороша, но, возможно, забыл, что в некоторых путях есть пробелы. Замена ';' с '" & Quot;» вместо этого будет вырезать все пути в строки в кавычках.
set _path="%PATH:;=" "%"
for %%p in (%_path%) do if not "%%~p"=="" echo %%~p
Итак, у вас есть ваши пути, отображаемые.
КомандаFOR в cmd имеет утомительную кривую обучения, в частности потому, что как переменные реагируют в выражениях () ... вы можете назначать любые переменные, но потом не можете читать обратно в (), если только вы не используйте " setlocal ENABLEDELAYEDEXPANSION " оператор, и, следовательно, также использовать переменные с !! вместо %% (! _var!)
Мне в настоящее время исключительно сценарий с cmd, для работы, пришлось изучить все это:)
У вас правильная идея, но for / f
предназначен для работы с многострочными файлами или командами, а не с отдельными строками.
В простейшем виде для
похож на Perl для
или на foreach
любого другого языка. Вы передаете ему список токенов, и он перебирает их, каждый раз вызывая одну и ту же команду.
for %a in (hello world) do @echo %a
Расширения просто предоставляют автоматические способы построения списка токенов. Причина, по которой ваш текущий код ничего не дает, заключается в том, что ;
является символом конца строки (комментария) по умолчанию. Но даже если вы измените это, вам придется использовать %% g, %% h, %% i, ...
для доступа к отдельным токенам, что серьезно ограничит ваш командный файл. р>
Самое близкое, к чему вы можете обратиться -
set TabbedPath=%PATH:;= %
for %%g in (%TabbedPath%) do echo %%g
Но это не сработает для указанных в кавычках путей, содержащих точку с запятой.
По моему опыту, для / l
и для / r
хороши для расширения существующих команд, но в остальном для
крайне ограничен. Вы можете сделать его немного более мощным (и запутанным) с отложенным расширением переменной ( cmd / v: on
), но это действительно хорошо только для списков имен файлов.
Я бы предложил использовать WSH или PowerShell, если вам нужно выполнить манипуляции со строками. Если вы пытаетесь написать whereis
для Windows, попробуйте where /?
.
Не удержался, выбрасывая это, старое, как этот поток ... Обычно, когда возникает необходимость перебирать каждый из файлов в PATH, все, что вам действительно нужно, это найти определенный файл ... Если в этом случае эта строка будет отображать первый каталог, в котором находится ваш файл:
(например: ищу java.exe)
for %%x in (java.exe) do echo %%~dp$PATH:x
Я знаю, что это СУПЕР-старое ... но просто для удовольствия я решил попробовать:
@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
.
for / f
выполняет итерации для каждого ввода строки, поэтому в вашей программе будет выводиться только первый путь.
ваша программа обрабатывает% PATH% как однострочный ввод и уменьшает его с помощью ;
, сначала помещает результат в %% g, затем выводит %% g (первый путь с разделителями).
FOR
по существу выполняет итерацию по " строкам " в наборе данных. В этом случае есть одна строка, которая содержит путь. " delims =; "
просто указывает на разделение на точки с запятой. Если вы измените тело на echo %% g, %% h, %% i, %% j, %% k
, вы увидите, что он обрабатывает ввод как одну строку и разбивает его на несколько токенов.
Это работает для меня:
@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
Вам необходимо дополнительно использовать часть 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 " ;. Я не делал это здесь, где я только повторяю токены.
Вы также можете сделать 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 на этот раз обрабатываются в обратном порядке, и как они теперь «означают» разные токены по сравнению с первым примером.
Так что это определенно не то краткое объяснение, о котором вы просили. Но, возможно, примеры помогают прояснить немного лучше ...
Вот хорошее руководство:
FOR / F - команда цикла: для набора файлов. р>
Команда FOR / F - Loop: с результатами другой команды. р>
FOR - команда Loop: все параметры Файлы, Каталог, Список. р>
[Полное руководство (команды Windows XP):
http://www.ss64.com/nt/index.html р>
Изменить . Извините, я не увидел, что ссылка уже была в OP, так как она показалась мне частью ссылки Amazon.
Это работает для меня, попробуйте.
for /f "delims=;" %g in ('echo %PATH%') do echo %g%
Это работает для меня, попробуйте.
для / f " токены = * delims =; " % g in ('echo% PATH%') делает эхо% g%