バッチファイルを書いていると「コマンドの実行結果を変数に入れて後続の処理に使いたい」という場面に必ずぶつかります。hostnameで取得したホスト名をファイル名に使う、ipconfigからIPアドレスだけを抽出する、wmicでOSバージョンを取得するなど、用途は非常に多岐にわたります。
バッチファイルでこれを実現する唯一の手段がfor /fのコマンド実行形式です。本記事では基本構文からtokens・delims・usebackqの詳細、実務でよく使う実用パターン、はまりやすい落とし穴まで体系的に解説します。
- for /f のコマンド実行形式の基本構文と動作原理
- tokens・delims・usebackq・skipの各オプションの意味と使い分け
- hostname・ipconfig・wmic・PowerShell・certutilなどの実用パターン
- 複数行出力の処理(全行連結・特定行の抽出・行番号付き処理)
- 空行の自動スキップ・特殊文字・ERRORLEVEL取得などの落とし穴と対処法
for /f のコマンド実行形式の基本
for /fはファイルやコマンド出力を1行ずつ読み込んで処理するコマンドです。コマンドの結果を変数に格納するには次の書式を使います。
rem シングルクォートでコマンドを囲む
for /f %%変数 in ('コマンド') do set "変数=%%変数"
rem 実例: hostname の結果を取得
@echo off
for /f %%A in ('hostname') do set "HOST=%%A"
echo ホスト名: %HOST%
ホスト名: DESKTOP-ABC1234
for /fがコマンドの出力を処理する流れを整理します。
| ステップ | 内容 |
|---|---|
| ① | シングルクォート内のコマンドをcmd.exeが実行する |
| ② | 標準出力(stdout)を1行ずつ読み込む(空行は自動でスキップ) |
| ③ | 各行をdelimsで指定した区切り文字で分割する |
| ④ | tokensで指定した列を変数(%%A, %%B…)に格納してdoブロックを実行する |
for /fは空行(改行だけの行)を無条件にスキップします。これは仕様であり回避できません。オプション詳解:tokens・delims・usebackq・skip
delims:区切り文字の指定
デフォルトの区切り文字はスペースとタブです。delims=で変更します。
| 指定 | 意味 | 使用例 |
|---|---|---|
delims=: |
コロンで分割 | ipconfig出力のラベル: 値を分割 |
delims=, |
カンマで分割 | CSV行の分割 |
delims== |
イコールで分割 | wmic … /value 出力の分割 |
delims= |
区切りなし(行全体を1トークン) | 行全体をそのまま取得したいとき |
tokens:取得する列番号の指定
区切り文字で分割した後、何列目を変数に入れるかを指定します。
rem tokens=1 : 1列目のみ(デフォルト)
rem tokens=2 : 2列目のみ
rem tokens=1,3: 1列目を%%A、3列目を%%B
rem tokens=2-4: 2~4列目を%%A, %%B, %%C
rem tokens=* : 全体を%%Aに
rem 例: "Name: John Doe" から "John Doe" 部分を取得
for /f "tokens=2* delims=:" %%A in ('echo Name: John Doe') do set "VAL=%%A"
usebackq:バッククォートとシングルクォートの役割を交換
コマンド内にシングルクォートを使う必要がある場合(PowerShellコマンドなど)はusebackqを使ってバッククォートでコマンドを囲みます。
rem 通常形式
for /f %%A in ('hostname') do set "HOST=%%A"
rem usebackq形式(PowerShellのシングルクォートを含むコマンドに必須)
for /f "usebackq delims=" %%A in (`powershell -Command "Get-Date -Format yyyyMMdd"`) do set "DATE=%%A"
skip:先頭N行をスキップ
rem net user の出力は最初の数行がヘッダー
for /f "skip=4 tokens=1" %%A in ('net user') do (
echo ユーザー: %%A
)
実用パターン集
パターン①:ホスト名を取得する
@echo off
for /f %%A in ('hostname') do set "HOST=%%A"
echo ホスト名: %HOST%
rem ログファイル名などに活用
set "LOG=C:\logs\process_%HOST%_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
パターン②:IPアドレスを取得する
@echo off
setlocal enabledelayedexpansion
for /f "tokens=2 delims=:" %%A in ('ipconfig ^| findstr /i "IPv4"') do (
set "IP=%%A"
)
set "IP=%IP: =%"
echo IPアドレス: %IP%
IPアドレス: 192.168.1.100
パターン③:Windowsバージョンを取得する
@echo off
for /f "tokens=* delims=" %%A in ('ver') do set "VER=%%A"
echo %VER%
rem wmic でOS名を取得(Caption=Windows 10 Pro の形式)
for /f "tokens=2 delims==" %%A in ('wmic os get Caption /value ^| findstr "="') do set "OS=%%A"
echo OS: %OS%
Microsoft Windows [Version 10.0.19045.3803] OS: Windows 10 Pro
パターン④:ディスクの空き容量を取得する
@echo off
for /f "tokens=2 delims==" %%A in (
'wmic logicaldisk where "DeviceID='C:'" get FreeSpace /value ^| findstr "="'
) do set "FREE_BYTES=%%A"
set /a FREE_GB=%FREE_BYTES:~0,-9%
echo Cドライブ空き容量: %FREE_GB% GB
Cドライブ空き容量: 128 GB
パターン⑤:プロセスの存在確認をする
@echo off
set "PROC=notepad.exe"
set "FOUND="
for /f "tokens=1" %%A in ('tasklist /fi "imagename eq %PROC%" ^| findstr /i "%PROC%"') do (
set "FOUND=%%A"
)
if defined FOUND (
echo [起動中] %PROC% が実行されています
) else (
echo [停止中] %PROC% は実行されていません
)
rem notepad.exe が起動中の場合: [起動中] notepad.exe が実行されています rem 起動していない場合: [停止中] notepad.exe は実行されていません
パターン⑥:PowerShellを組み合わせて柔軟な値を取得する
バッチファイルの文字列処理に限界を感じたら、PowerShellを呼び出して結果を変数に取り込む方法が強力です。
@echo off rem 日時をyyyy-MM-dd_HHmmss形式で取得 for /f "usebackq delims=" %%A in (`powershell -NoProfile -Command "Get-Date -Format 'yyyy-MM-dd_HHmmss'"`) do set "NOW=%%A" echo 現在日時: %NOW% rem 特定拡張子のファイル数を取得 for /f "usebackq delims=" %%A in (`powershell -NoProfile -Command "(Get-ChildItem 'C:\work' -Filter *.txt).Count"`) do set "COUNT=%%A" echo txtファイル数: %COUNT%
現在日時: 2026-03-21_143052 txtファイル数: 37
パターン⑦:最新ファイル名を取得する
@echo off
rem /o:d で更新日時順ソート、ループ最後の行が最新ファイル
set "LATEST="
for /f "delims=" %%A in ('dir /b /a:-d /o:d "C:\work\*.log"') do set "LATEST=%%A"
if defined LATEST (
echo 最新ログ: %LATEST%
) else (
echo ログファイルが見つかりません
)
最新ログ: process_20260321.log
複数行の出力を処理する
全行を連結して1つの変数に格納する
@echo off
setlocal enabledelayedexpansion
set "ALL="
for /f "delims=" %%A in ('dir /b "C:\work\*.txt"') do (
if defined ALL (
set "ALL=!ALL!, %%A"
) else (
set "ALL=%%A"
)
)
echo ファイル一覧: %ALL%
ファイル一覧: document_A.txt, document_B.txt, notes.txt
行番号付きで処理する
@echo off
setlocal enabledelayedexpansion
set LINE=0
for /f "delims=" %%A in ('dir /b "C:\work\*.txt"') do (
set /a LINE+=1
echo 行 !LINE!: %%A
)
echo 合計 %LINE% ファイル
N行目だけを取得する
@echo off
setlocal enabledelayedexpansion
set LINE=0
set "TARGET="
for /f "delims=" %%A in ('コマンド') do (
set /a LINE+=1
if !LINE! equ 2 set "TARGET=%%A"
)
echo 2行目: %TARGET%
よくある落とし穴と対処法
落とし穴①:コマンド内の特殊文字をエスケープしていない
for /f内のコマンドは内部でcmd.exeから呼び出されるため、|・&・>・<などの特殊文字はキャレット(^)でエスケープが必要です。
rem エラーになる
for /f "tokens=2 delims=:" %%A in ('ipconfig | findstr "IPv4"') do set "IP=%%A"
for /f "tokens=2 delims=:" %%A in ('ipconfig ^| findstr "IPv4"') do set "IP=%%A"
落とし穴②:遅延展開を使わずにループ内変数を更新している
@echo off
set "RESULT="
for /f %%A in ('dir /b *.txt') do (
set "RESULT=%RESULT% %%A" rem 常に空のまま
)
echo %RESULT% rem 空になる
@echo off
setlocal enabledelayedexpansion
set "RESULT="
for /f %%A in ('dir /b *.txt') do (
set "RESULT=!RESULT! %%A" rem 正しく追記される
)
echo %RESULT%
落とし穴③:ERRORLEVEL をループ内で確認できない
for /fのin ('command')構文では、コマンドのERRORLEVELが変数に反映されません。コマンドの成否を確認したい場合は事前に実行してから結果ファイル経由で処理します。
@echo off
net user %USERNAME% > "%TEMP%\user_info.tmp" 2>nul
if %ERRORLEVEL% neq 0 (
echo [ERROR] ユーザー情報の取得に失敗しました
exit /b 1
)
for /f "skip=4 tokens=1" %%A in ("%TEMP%\user_info.tmp") do echo %%A
del "%TEMP%\user_info.tmp" >nul 2>&1
落とし穴④:wmicの /value 出力を正しく処理する
@echo off
rem findstr で = を含む行だけ抽出してからイコールで分割
for /f "tokens=2 delims==" %%A in (
'wmic os get Caption /value ^| findstr "="'
) do set "OS_NAME=%%A"
echo OS: %OS_NAME%
落とし穴⑤:複雑なコマンドは一時ファイル経由で処理する
@echo off
set "TMP_FILE=%TEMP%\cmd_output.tmp"
ipconfig /all > "%TMP_FILE%" 2>&1
for /f "tokens=2 delims=:" %%A in ('findstr /i "IPv4" "%TMP_FILE%"') do (
set "IP=%%A"
)
set "IP=%IP: =%"
echo IP: %IP%
del "%TMP_FILE%" >nul 2>&1
実務で使える完全テンプレート
ここまでのパターンを組み合わせた実務テンプレートです。コピーして自分の環境に合わせて修正してください。
@echo off
setlocal enabledelayedexpansion
:: ホスト名取得
for /f %%A in ('hostname') do set "HOST=%%A"
:: IPアドレス取得
for /f "tokens=2 delims=:" %%A in ('ipconfig ^| findstr /i "IPv4"') do set "IP=%%A"
set "IP=%IP: =%"
:: OSバージョン取得
for /f "tokens=2 delims==" %%A in ('wmic os get Caption /value ^| findstr "="') do set "OS=%%A"
:: Cドライブ空き容量取得(GB)
for /f "tokens=2 delims==" %%A in (
'wmic logicaldisk where "DeviceID='C:'" get FreeSpace /value ^| findstr "="'
) do set "FREE_BYTES=%%A"
set /a FREE_GB=%FREE_BYTES:~0,-9%
:: 結果表示 & ログ保存
set "LOG=C:\logs\sysinfo_%HOST%_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
if not exist "C:\logs" mkdir "C:\logs"
(
echo ホスト名 : %HOST%
echo IPアドレス : %IP%
echo OS : %OS%
echo C空き容量 : %FREE_GB% GB
echo 取得日時 : %DATE% %TIME%
) | tee "%LOG%"
echo.
echo ログ保存先: %LOG%
ホスト名 : DESKTOP-ABC1234 IPアドレス : 192.168.1.100 OS : Windows 10 Pro C空き容量 : 128 GB 取得日時 : 2026/03/21 14:30:52.34 ログ保存先: C:\logs\sysinfo_DESKTOP-ABC1234_20260321.log
> "%LOG%"でリダイレクトするか、echo ... >> "%LOG%"で1行ずつ追記してください。PowerShellのTee-Objectを組み合わせる方法もあります。for /f のオプション早見表
| オプション | 説明 | 例 |
|---|---|---|
delims=文字 |
区切り文字を指定(複数可) | delims=:, |
delims= |
区切りなし(行全体を1トークン) | delims= |
tokens=N |
N列目を取得 | tokens=2 |
tokens=N,M |
N列目とM列目を取得 | tokens=1,3 |
tokens=N* |
N列目以降すべてを取得 | tokens=2* |
tokens=* |
行全体を1トークンとして取得 | tokens=* |
skip=N |
先頭N行をスキップ | skip=1 |
usebackq |
バッククォートでコマンドを囲む形式に変更 | usebackq delims= |
eol=文字 |
行頭がこの文字の行をスキップ | eol=; |
関連記事
- 【bat】FOR文の使い方完全ガイド(for /f のファイル読み込み形式・数値ループ等の解説)
- 【bat】certutilでファイルのハッシュ値を取得・検証する完全ガイド(for /f でcertutil出力からハッシュ値を抽出する実例)
- 【bat】バッチファイルで条件分岐する方法完全ガイド(取得した値をif文で条件分岐する)
よくある質問
for /fが読み込むのは標準出力(stdout)のみです。エラーメッセージもstdoutに出力するには2>&1リダイレクトをコマンドに追加します。例:for /f %%A in ('command 2^>^&1') do ...。tokens=1,2,3と指定すると、1列目が%%A、2列目が%%B、3列目が%%Cに格納されます。変数はアルファベット順に最大26個まで取得できます。for /fは出力がない場合doブロックを実行しません。事前にset "VAR=デフォルト値"しておけば、出力がなければデフォルト値、出力があれば実際の値が格納されます。for変数は%%A(%%2つ)で書きますが、コマンドプロンプトで直接入力するときは%A(%1つ)で書きます。バッチファイル内では%がパラメータ展開として使われるため%%が必要です。tokens=2*は「2列目以降すべて」を意味します。%%Aに2列目、%%Bに3列目以降の残り全体が入ります。コロンが1つしかない行では2列目の文字列が%%Aに入り、%%Bは空になるのが正常な動作です。