【bat】バッチファイルで文字列を結合する方法完全ガイド|変数連結・ループ内累積・区切り文字・パス組み立て・CSV生成まで徹底解説

【bat】バッチファイルで文字列を結合する方法 bat

バッチファイルで文字列を結合するには、set コマンドで変数を並べて書くだけです。しかし実務では「ループの中で累積結合する・区切り文字を挟む・コマンド結果を繋げる・パスやCSV行を動的に組み立てる」など、一歩踏み込んだ操作が必要になります。この記事では基本から実践パターンまで体系的に解説します。

この記事でわかること

  • 変数を並べる基本の文字列結合
  • スペース・カンマ・スラッシュなど区切り文字を挟んで結合する方法
  • ループ内で文字列を累積結合する方法(enabledelayedexpansion が必須な理由)
  • コマンドの実行結果を変数に取り込んで結合する方法
  • 先頭・末尾の余分なスペースを除去するテクニック
  • パス・ファイル名の動的組み立て
  • CSV行やリストを動的に生成する方法
  • PowerShell を使った文字列結合
スポンサーリンク

1. 基本の文字列結合

バッチファイルで文字列を結合するには、set の右辺に変数を並べるだけです。変数と変数の間に何も書かなければそのまま連結、スペースや記号を書けば区切り文字になります。

@echo off
setlocal

set FIRST=Hello
set LAST=World

:: 直接連結
set RESULT=%FIRST%%LAST%
echo %RESULT%
:: → HelloWorld

:: スペースを挟む
set RESULT=%FIRST% %LAST%
echo %RESULT%
:: → Hello World

:: カンマ区切り
set RESULT=%FIRST%,%LAST%
echo %RESULT%
:: → Hello,World

:: アンダースコア区切り
set RESULT=%FIRST%_%LAST%
echo %RESULT%
:: → Hello_World
記述例 結果 説明
set R=%A%%B% HelloWorld 直接連結
set R=%A% %B% Hello World スペース区切り
set R=%A%,%B% Hello,World カンマ区切り(CSV等)
set R=%A%_%B% Hello_World アンダースコア区切り(ファイル名等)
set R=%A%\%B% Hello\World バックスラッシュ区切り(パス組み立て)

2. ループ内で文字列を累積結合する方法

ループの中で文字列を少しずつ積み上げていく「累積結合」は、バッチ特有の重要な落とし穴があります。%変数% はループ実行前に一度だけ展開されるため、そのままでは累積できません。

for ループ内で %変数% を使う累積結合はバグになる
set str=%str%_%%i のように for ループ内で %str% を参照しても、ループ開始時の値(変更前)が使われてしまい正しく累積できません。setlocal enabledelayedexpansion + !str! を使う必要があります。

2-1. NG パターン(%変数% のまま)と OK パターン(!変数!)の比較

@echo off

:: NG: %str% はループ開始前に展開されるため累積されない
setlocal
set STR=Base
for %%I in (1 2 3) do (
    set STR=%STR%_%%I
    :: %STR% は常に "Base" のまま(変化しない)
)
echo %STR%
:: 結果: Base_3  (_1 _2 が累積されず、最後の _3 だけ)

:: OK: setlocal enabledelayedexpansion + !STR! で累積できる
setlocal enabledelayedexpansion
set STR=Base
for %%I in (1 2 3) do (
    set STR=!STR!_%%I
)
echo !STR!
:: 結果: Base_1_2_3  ← 正しく累積

2-2. リストをカンマ区切りで結合する

@echo off
setlocal enabledelayedexpansion

set RESULT=

for %%I in (apple banana cherry date) do (
    :: 最初の要素はカンマなし、2個目以降はカンマを先頭に付ける
    if "!RESULT!"=="" (
        set RESULT=%%I
    ) else (
        set RESULT=!RESULT!,%%I
    )
)

echo %RESULT%
:: 結果: apple,banana,cherry,date

2-3. ファイル一覧をスペース区切りで結合する

@echo off
setlocal enabledelayedexpansion

set FILE_LIST=

for %%F in (C:\work\*.txt) do (
    if "!FILE_LIST!"=="" (
        set FILE_LIST=%%~nxF
    ) else (
        set FILE_LIST=!FILE_LIST! %%~nxF
    )
)

echo ファイル一覧: !FILE_LIST!
:: 結果: ファイル一覧: a.txt b.txt c.txt

setlocal enabledelayedexpansion!変数! の詳細は setlocal enabledelayedexpansion 完全ガイド も参照してください。

3. コマンドの実行結果を変数に取り込んで結合する

for /f を使うと、コマンドの出力結果を変数に格納できます。日付・ホスト名・IP アドレスなどを動的に取り込んでメッセージやファイル名に結合するのに便利です。

@echo off
setlocal

:: ホスト名を取得して変数に結合
for /f %%H in ('hostname') do set HOST=%%H
set MSG=サーバー名: %HOST% の処理が完了しました
echo %MSG%

:: 日付を地域設定非依存で取得(PowerShell 経由)
for /f %%D in ('powershell -Command "Get-Date -Format yyyyMMdd"') do set TODAY=%%D
set LOGFILE=log_%TODAY%.txt
echo ログファイル: %LOGFILE%
:: 結果: ログファイル: log_20250317.txt

:: IP アドレスを取得して結合
for /f "tokens=2 delims=:" %%I in ('ipconfig ^| findstr /i "IPv4"') do (
    set IP=%%I
    :: 先頭の空白を除去
    set IP=!IP:~1!
    :: 最初のアドレスだけ使うため goto で抜ける
    goto :got_ip
)
:got_ip
echo IPアドレス: %IP%
set REPORT=ホスト=%HOST%, IP=%IP%, 日付=%TODAY%
echo %REPORT%

4. 先頭・末尾の余分なスペースを除去して結合する

set /p でユーザーが入力した値や、コマンド出力を for /f で取得した場合に先頭や末尾にスペースが入ることがあります。そのまま結合するとズレが生じます。

@echo off
setlocal enabledelayedexpansion

:: set /p で入力を受け取る場合
set /p FIRST_NAME=名前を入力: 
set /p LAST_NAME=苗字を入力: 

:: 末尾スペースのトリム(for /f で再読み込み)
for /f "tokens=* delims= " %%V in ("!FIRST_NAME!") do set FIRST_NAME=%%V
for /f "tokens=* delims= " %%V in ("!LAST_NAME!") do set LAST_NAME=%%V

:: 結合
set FULL_NAME=!LAST_NAME! !FIRST_NAME!
echo フルネーム: !FULL_NAME!
set /p 入力の末尾スペース問題
set /p VAR= で入力を受け取ると、Enterキーの前に誤ってスペースが押された場合に末尾スペースが入ります。for /f "tokens=* delims= " %%V in ("!VAR!") do set VAR=%%V でトリムできます。詳細は 変数の末尾に余計な空白が入ってしまうときの対策 も参照してください。

5. パス・ファイル名を動的に組み立てる

パスやファイル名は文字列結合の最も頻繁なユースケースです。変数を組み合わせて安全にパスを組み立てる方法を紹介します。

@echo off
setlocal

:: 各パーツを変数で定義
set BASE_DIR=C:\work
set PROJECT=myapp
set ENV=production
set EXT=.log

:: for /f で日付を取得
for /f %%D in ('powershell -Command "Get-Date -Format yyyyMMdd"') do set DATE=%%D

:: パスを組み立てる
set LOG_DIR=%BASE_DIR%\%PROJECT%\logs
set LOG_FILE=%LOG_DIR%\%ENV%_%DATE%%EXT%

echo ログディレクトリ : %LOG_DIR%
echo ログファイル     : %LOG_FILE%
:: 結果: C:\work\myapp\logs\production_20250317.log

:: フォルダが存在しない場合は作成
if not exist "%LOG_DIR%\" mkdir "%LOG_DIR%"

:: ログ書き込み
echo [%DATE%] 処理開始 >> "%LOG_FILE%"

5-1. %~dp0 を使ったバッチ基準のパス組み立て

@echo off
setlocal

:: バッチの場所を基準に各パスを組み立て
set BASE=%~dp0
set CONFIG=%BASE%config\settings.ini
set OUTPUT=%BASE%output\
set LOG=%BASE%logs\run.log

echo 設定ファイル : %CONFIG%
echo 出力先       : %OUTPUT%
echo ログファイル : %LOG%

6. CSV 行・ヘッダーを動的に生成する

フォルダ内のファイル一覧や処理結果を CSV 形式で出力する場合、カンマ区切りで結合した行を作ることが多くあります。

@echo off
setlocal enabledelayedexpansion

set OUTPUT=C:\work\filelist.csv

:: ヘッダー行を文字列結合で作成
set HEADER=ファイル名,サイズ,更新日時
echo %HEADER% > "%OUTPUT%"

:: ファイル一覧を CSV 行として結合
for %%F in (C:\work\*.txt) do (
    set NAME=%%~nxF
    set SIZE=%%~zF
    set MTIME=%%~tF
    :: カンマ区切りで結合してCSVに追記
    set ROW=!NAME!,!SIZE!,!MTIME!
    echo !ROW! >> "%OUTPUT%"
)

echo CSV を作成しました: %OUTPUT%

6-2. for /f で CSV の列を読んで新しい行を組み立てる

@echo off
setlocal enabledelayedexpansion

:: input.csv から列を読み込み、姓名を結合した新しいCSVを作成
:: input.csv 形式: ID,姓,名,部署
set INPUT=%~dp0input.csv
set OUTPUT=%~dp0output.csv

echo ID,フルネーム,部署 > "%OUTPUT%"

for /f "usebackq skip=1 tokens=1,2,3,4 delims=," %%A in ("%INPUT%") do (
    :: 姓(%%B)と名(%%C)をスペースで結合
    set FULLNAME=%%B %%C
    :: ID,フルネーム,部署 の形式で出力
    set ROW=%%A,!FULLNAME!,%%D
    echo !ROW! >> "%OUTPUT%"
)

echo 変換完了: %OUTPUT%

7. 番号付き変数(配列風)を結合して使う

バッチには配列がありませんが、VAR_1VAR_2 のように番号付き変数で代用できます。遅延展開を使えばループで動的にアクセスできます。

@echo off
setlocal enabledelayedexpansion

:: 配列風に変数を定義
set ITEM_1=東京
set ITEM_2=大阪
set ITEM_3=名古屋
set ITEM_COUNT=3

:: ループで結合(区切り文字は「・」)
set RESULT=
for /l %%I in (1,1,%ITEM_COUNT%) do (
    if "!RESULT!"=="" (
        set RESULT=!ITEM_%%I!
    ) else (
        set RESULT=!RESULT!・!ITEM_%%I!
    )
)

echo !RESULT!
:: 結果: 東京・大阪・名古屋

8. PowerShell を使った文字列結合

PowerShell を呼び出すと -join 演算子や文字列フォーマットが使え、より柔軟な結合ができます。結果をバッチ変数に取り込むことも可能です。

@echo off
setlocal

:: PowerShell で配列を結合(カンマ区切り)
for /f %%R in ('powershell -Command "'apple','banana','cherry' -join ','""') do set RESULT=%%R
echo %RESULT%
:: 結果: apple,banana,cherry

:: PowerShell でフォーマット文字列を使った結合
set HOST_NAME=%COMPUTERNAME%
for /f %%D in ('powershell -Command "Get-Date -Format 'yyyyMMdd_HHmmss'"') do set DT=%%D
set FILENAME=%HOST_NAME%_%DT%.log
echo %FILENAME%
:: 結果: MYPC_20250317_143022.log

9. 実践例3本

実践例1:システム情報を結合してレポートファイルに書き出す

@echo off
setlocal enabledelayedexpansion

:: システム情報を収集して1行にまとめる
for /f %%H in ('hostname') do set HOST=%%H
for /f %%U in ('echo %USERNAME%') do set USER=%%U
for /f %%D in ('powershell -Command "Get-Date -Format yyyyMMdd_HHmmss"') do set DT=%%D
for /f "tokens=2 delims==" %%V in ('wmic os get Caption /value ^| findstr "Caption"') do set OS=%%V

:: フィールドをCSV形式で結合
set REPORT_LINE=%HOST%,%USER%,%DT%,%OS%

set REPORT_FILE=%~dp0system_report.csv

:: ヘッダーが存在しない場合のみ追加
if not exist "%REPORT_FILE%" (
    echo ホスト名,ユーザー名,日時,OS > "%REPORT_FILE%"
)

echo %REPORT_LINE% >> "%REPORT_FILE%"
echo レポートに追記しました: %REPORT_FILE%

実践例2:複数のテキストファイルを読み込んで1行のサマリを作る

@echo off
setlocal enabledelayedexpansion

:: C:\work\status\ 配下の *.txt を読み込んで状態サマリを結合
:: 各ファイルの1行目が状態テキスト
set SUMMARY=
set STATUS_DIR=%~dp0status

for %%F in ("%STATUS_DIR%\*.txt") do (
    :: ファイルの1行目を読む
    for /f "usebackq delims=" %%L in ("%%F") do (
        set LINE=%%L
        goto :got_line
    )
    :got_line
    :: ファイル名と内容を結合
    set ENTRY=[%%~nF: !LINE!]
    if "!SUMMARY!"=="" (
        set SUMMARY=!ENTRY!
    ) else (
        set SUMMARY=!SUMMARY! !ENTRY!
    )
)

echo サマリ: !SUMMARY!

実践例3:引数とシステム情報を結合してバックアップフォルダ名を生成する

@echo off
setlocal

:: 使い方: backup_name.bat プロジェクト名
if "%~1"=="" (
    echo 使い方: %~nx0 プロジェクト名
    exit /b 1
)

set PROJECT=%~1

:: 日時・ホスト名を取得
for /f %%D in ('powershell -Command "Get-Date -Format yyyyMMdd_HHmmss"') do set DT=%%D
for /f %%H in ('hostname') do set HOST=%%H

:: バックアップフォルダ名を結合で組み立て
set BACKUP_NAME=%PROJECT%_%DT%_%HOST%
set BACKUP_PATH=D:\backups\%BACKUP_NAME%

echo バックアップ先: %BACKUP_PATH%
mkdir "%BACKUP_PATH%"

:: xcopy でバックアップ
xcopy /e /i /q "C:\projects\%PROJECT%" "%BACKUP_PATH%"
if %errorlevel% equ 0 (
    echo [OK] バックアップ完了: %BACKUP_PATH%
) else (
    echo [ERROR] バックアップ失敗
    exit /b 1
)

10. まとめ:文字列結合チートシート

やりたいこと コード例 ポイント
直接連結 set R=%A%%B% そのまま並べるだけ
区切り文字付き set R=%A%,%B% 変数の間に記号を書く
ループ内累積 set R=!R!%%I setlocal enabledelayedexpansion + ! が必須
先頭要素のカンマなし if "!R!"=="" (set R=%%I) else (set R=!R!,%%I) 空チェックで分岐
コマンド結果を結合 for /f %%V in ('cmd') do set VAR=%%V for /f で変数に格納
CSV行を生成 set ROW=!A!,!B!,!C! カンマ区切りで並べる
パスを組み立て set PATH=%BASE%\%SUB%\%FILE% \ を区切りに変数を連結
PowerShell で結合 for /f %%R in ('ps -Command "join..."') do -join 演算子が使える

文字列の切り出し・抽出については バッチファイルで文字列を切り出して抽出する方法、文字列の置換については バッチファイルで文字列置換する方法完全ガイド も参照してください。

FAQ

Qループ内で文字列を結合しても最後の値しか残りません。

Afor ループ内で %変数% を使うと、ループ開始前の値に固定されるため累積できません。setlocal enabledelayedexpansion を宣言して !変数! を使ってください。詳細は 変数展開が思った通りに動かない原因と修正方法 も参照してください。

Q結合後の文字列の先頭にスペースが入ってしまいます。

Aループで最初の要素にセパレータが付いてしまうことが原因です。if "!RESULT!"=="" (set RESULT=%%I) else (set RESULT=!RESULT!,%%I) のように空チェックで分岐して先頭要素の前には区切り文字を付けないパターンで回避できます。

Q変数の中に & や ^ などの特殊文字が含まれていると結合できません。

Aバッチの特殊文字(&^|>< など)を変数値として扱う場合は ^(キャレット)でエスケープするか、setlocal enabledelayedexpansion + ! を使うと特殊文字の影響を軽減できます。

Q文字列の長さに上限はありますか?

Aバッチの変数値は最大 8191 文字です。長い文字列を結合し続けるとこの制限に引っかかることがあります。大量のデータを扱う場合はファイルに書き出す方式や PowerShell を使う方が安全です。

Qset /p で入力した値を結合すると末尾に余計なスペースが入ります。

Aユーザーがスペースを押してからEnterした場合に末尾スペースが残ります。for /f "tokens=* delims= " %%V in ("!VAR!") do set VAR=%%V でトリムできます。詳細は 変数の末尾に余計な空白が入ってしまうときの対策 も参照してください。

Qecho で結合した文字列を表示すると、変数が展開されずそのまま出力されます。

A@echo off がないと echo の前にパスが表示されることがあります。また setlocal enabledelayedexpansion 使用時に %! を混在させると意図しない動作になります。echo !VAR!echo %VAR% のどちらかに統一してください。