cmd バッチ ファイルでの「FOR」はどのように機能しますか?
-
03-07-2019 - |
質問
私は 20 年間、数十の言語でプログラミングしてきましたが、どんなに頑張っても Windows cmd シェル バッチ ファイルで "FOR" がどのように機能するのか理解できませんでした。私は読む
http://www.ss64.com/nt/for.html
インターネット上の他の記事もいくつかありますが、依然として混乱しており、何も達成できません。
誰かが「FOR」が一般的にどのように機能するかについて簡潔に説明できますか?
もう少し具体的な質問については、%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
)
)
ああ!バッチファイルプログラミングが嫌いです!!
更新
Markの解決策は簡単ですが、空白を含むパスでは機能しません。これは、Markのソリューションの少し変更されたバージョンです
echo off
setlocal enabledelayedexpansion
set NonBlankPath=%PATH: =#%
set TabbedPath=%NonBlankPath:;= %
for %%g in (%TabbedPath%) do (
set GG=%%g
echo !GG:#= !
)
他のヒント
マークのアイデアは良かったのですが、パスにスペースが含まれていることを忘れたのかもしれません。代わりに ';' を '" "' に置き換えると、すべてのパスが引用符で囲まれた文字列に切り取られます。
set _path="%PATH:;=" "%"
for %%p in (%_path%) do if not "%%~p"=="" echo %%~p
ここにパスが表示されています。
cmd の FOR コマンドは、特に () ステートメント内で変数がどのように反応するかが原因で、学習に時間がかかります。任意の変数を割り当てることができますが、「setlocal ENABLEDELAYEDEXPANSION」ステートメントを使用しない限り、() 内で読み取ることはできないため、%% の (! の代わりに !! を使用して変数を使用することもできます)。 _var!)
私は現在、仕事のためにもっぱらcmdを使ってスクリプトを作成していますが、これをすべて学ぶ必要がありました:)
正しいアイデアはありますが、 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を使用することをお勧めします。 Windows用の whereis
を作成しようとしている場合は、 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%を1行の入力として扱い、;
で区切り、最初の結果を%% gに入れてから、%% g(最初のデリミテッドパス)を出力します。
FOR
は、本質的に" lines"を繰り返し処理しています。データセット内。この場合、パスを含む1行があります。 " delims =;"
は、セミコロンで区切るように指示しているだけです。本文を echo %% g、%% h、%% i、%% j、%% k
に変更すると、入力が1行として扱われ、壊れていることがわかります。複数のトークンに。
これは私のために働く:
@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
for
ループで許可されるオプションの tokens = 1,2、...
部分を追加で使用する必要があります。これにより、必要な処理が実行されます。
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がどのように逆順に処理され、最初の例と比較して異なるトークンを「意味する」ことに注意してください。
したがって、これはあなたが求めた簡潔な説明ではないことは確かです。しかし、この例はもう少しわかりやすくなるかもしれません...
ここに良いガイドがあります:
FOR / F-ループコマンド:別のコマンドの結果に対して。
FOR-ループコマンド:すべてのオプションファイル、ディレクトリ、リスト。
[ガイド全体(Windows XPコマンド):
http://www.ss64.com/nt/index.html
編集:申し訳ありませんが、Amazonリンクの一部として表示されるため、リンクが既にOPにあることは確認できませんでした。
それは私のために動作します、試してください。
for /f "delims=;" %g in ('echo %PATH%') do echo %g%
それは私にとってはうまくいきます、試してみてください。
for /f "tokens=* delims=;" %g in ('echo %PATH%') do echo %g%