【bat】外部コマンドの結果を変数に格納する方法完全ガイド|for /f・tokens・delims・usebackq・複数行・実用パターンまで徹底解説

バッチファイルを書いていると「コマンドの実行結果を変数に入れて後続の処理に使いたい」という場面に必ずぶつかります。hostnameで取得したホスト名をファイル名に使う、ipconfigからIPアドレスだけを抽出する、wmicでOSバージョンを取得するなど、用途は非常に多岐にわたります。

バッチファイルでこれを実現する唯一の手段がfor /fのコマンド実行形式です。本記事では基本構文からtokensdelimsusebackqの詳細、実務でよく使う実用パターン、はまりやすい落とし穴まで体系的に解説します。

この記事で分かること

  • 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:取得する列番号の指定

区切り文字で分割した後、何列目を変数に入れるかを指定します。

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を使ってバッククォートでコマンドを囲みます。

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行をスキップ

skipでヘッダー行を飛ばす
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アドレスを取得する

IPv4アドレスを取得
@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バージョンを取得する

OSバージョン情報を取得
@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

パターン④:ディスクの空き容量を取得する

Cドライブの空き容量を取得(GB)
@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を呼び出して結果を変数に取り込む方法が強力です。

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行目だけを取得する

2行目だけを取得
@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から呼び出されるため、|&><などの特殊文字はキャレット(^)でエスケープが必要です。

NG: パイプがエスケープされていない
rem エラーになる
for /f "tokens=2 delims=:" %%A in ('ipconfig | findstr "IPv4"') do set "IP=%%A"
OK: パイプを ^ でエスケープ
for /f "tokens=2 delims=:" %%A in ('ipconfig ^| findstr "IPv4"') do set "IP=%%A"

落とし穴②:遅延展開を使わずにループ内変数を更新している

NG: ループ内で %VAR% を使う
@echo off
set "RESULT="
for /f %%A in ('dir /b *.txt') do (
    set "RESULT=%RESULT% %%A"  rem 常に空のまま
)
echo %RESULT%  rem 空になる
OK: setlocal enabledelayedexpansion と !VAR! を使う
@echo off
setlocal enabledelayedexpansion
set "RESULT="
for /f %%A in ('dir /b *.txt') do (
    set "RESULT=!RESULT! %%A"  rem 正しく追記される
)
echo %RESULT%

落とし穴③:ERRORLEVEL をループ内で確認できない

for /fin ('command')構文では、コマンドのERRORLEVELが変数に反映されません。コマンドの成否を確認したい場合は事前に実行してから結果ファイル経由で処理します。

OK: 一時ファイル経由で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 出力を正しく処理する

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

実務で使える完全テンプレート

ここまでのパターンを組み合わせた実務テンプレートです。コピーして自分の環境に合わせて修正してください。

システム情報収集テンプレート(ホスト名・IP・OS・ディスク空き容量)
@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
teeコマンドが使えない場合: Windowsのteeはデフォルトでは存在しません。標準出力をファイルにも出力したい場合は> "%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=;

関連記事

よくある質問

Q. for /f でコマンドを実行したとき、標準エラー出力(stderr)も取り込まれますか?
A. いいえ、for /fが読み込むのは標準出力(stdout)のみです。エラーメッセージもstdoutに出力するには2>&1リダイレクトをコマンドに追加します。例:for /f %%A in ('command 2^>^&1') do ...
Q. for /f の変数は %%A から始まりますが、複数の列を取得するとき %%B, %%C はどう対応しますか?
A. tokens=1,2,3と指定すると、1列目が%%A、2列目が%%B、3列目が%%Cに格納されます。変数はアルファベット順に最大26個まで取得できます。
Q. コマンドの出力が空のときに変数をデフォルト値にしたい場合は?
A. for /fは出力がない場合doブロックを実行しません。事前にset "VAR=デフォルト値"しておけば、出力がなければデフォルト値、出力があれば実際の値が格納されます。
Q. バッチファイル内では %% が必要ですが、コマンドプロンプトで直接入力するときと何が違いますか?
A. バッチファイル内ではfor変数は%%A(%%2つ)で書きますが、コマンドプロンプトで直接入力するときは%A(%1つ)で書きます。バッチファイル内では%がパラメータ展開として使われるため%%が必要です。
Q. “tokens=2* delims=:” とすると %%B が空になることがあります。なぜですか?
A. tokens=2*は「2列目以降すべて」を意味します。%%Aに2列目、%%Bに3列目以降の残り全体が入ります。コロンが1つしかない行では2列目の文字列が%%Aに入り、%%Bは空になるのが正常な動作です。