web-dev-qa-db-ja.com

cmdバッチファイルで「FOR」はどのように機能しますか?

私は20年にわたって何十もの言語でプログラミングを行ってきましたが、Windows cmd Shellバッチファイルで "FOR"がどのように機能するかを理解することはできませんでした。私は読む

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

それは、すべてではなく、最初のパスのみを表示します。どうして ?私が間違っているのは何ですか?

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

ああ !バッチファイルプログラミングが嫌いです!!

更新済み

マークのソリューションは簡単ですが、空白を含むパスでは機能しません。これは、Markのソリューションの少し修正されたバージョンです

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

そのため、ここにパスが表示されます。

CmdのFORコマンドには、退屈な学習曲線があります。特に、変数が()のステートメント内でどのように反応するかによって...任意の変数を割り当てることができますが、 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 /lfor /rは既存のコマンドの拡張に適していますが、それ以外の場合はforは非常に制限されています。遅延変数展開(cmd /v:on)を使用すると、少し強力に(そして混乱を招くように)できますが、実際にはファイル名のリストにのみ適しています。

文字列操作を実行する必要がある場合は、WSHまたはPowerShellを使用することをお勧めします。 Windows用のwhereisを作成しようとしている場合は、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

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が逆の順序で処理され、最初の例と比較して異なるトークンを「意味する」ことに注意してください。

したがって、これは確かにあなたが求めた簡潔な説明ではありません。しかし、この例はもう少し明確にするのに役立つかもしれません...

2
Kurt Pfeifle

for /fは行ごとに入力を繰り返すため、プログラムでは最初のパスのみが出力されます。

プログラムは%PATH%を1行の入力として扱い、;、最初の結果を%% gに入れてから、%% g(最初のデリミテッドパス)を出力します。

2
Francis

FORは基本的に、データセットの「行」を反復処理します。この場合、パスを含む1行があります。 "delims=;"は、セミコロンで区切るように伝えています。本文をecho %%g,%%h,%%i,%%j,%%kに変更すると、入力が1行として扱われ、複数のトークンに分割されていることがわかります。

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-ループコマンド:一連のファイルに対して

FOR/F-ループコマンド:別のコマンドの結果に対して

FOR-ループコマンド:すべてのオプションファイル、ディレクトリ、リスト

[ガイド全体(Windows XPコマンド):

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

Edit:申し訳ありませんが、Amazonリンクの一部として表示されたため、リンクが既にOPにあることはわかりませんでした。

1
TFM

それは私のために働く、それを試してみてください。

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