【bat】バッチファイルで文字列置換する方法完全ガイド|set変数置換・PowerShell・ファイル内一括置換・正規表現・実践パターンまで

バッチファイルで文字列を置換したい場面は多岐にわたります。ログファイルの整形・設定ファイルの書き換え・ファイル名の一括変換・データのマスキングなど、文字列置換は自動化の中核技術です。

この記事では バッチファイルで文字列置換する全手法 を体系的に解説します。set変数の置換構文・for /f でのファイル1行ずつ置換・PowerShell による一括置換・正規表現対応まで網羅します。

この記事でわかること

  • set変数の %変数:検索=置換% 構文の使い方
  • 遅延展開(!変数:検索=置換!)での動的置換
  • for /f でテキストファイルを1行ずつ置換して書き出す方法
  • PowerShell の Get-Content -replace でファイル内を一括置換する方法
  • 正規表現を使った高度な置換
  • 落とし穴5選・実践例3本・FAQ6問
スポンサーリンク

1. バッチファイルの文字列置換3つのアプローチ

方法 用途 正規表現 大文字小文字
%変数:old=new% 変数内の文字列を置換 非対応 区別なし
for /f + set置換 テキストファイルを1行ずつ置換 非対応 区別なし
PowerShell -replace ファイル内を一括置換・正規表現対応 対応 区別なし(-creplaceで区別あり)

2. set変数置換の基本

バッチファイルの set コマンドには変数値の一部を置換する構文が組み込まれています。

2-1. 基本構文

書式:%変数名:検索文字列=置換文字列%

@echo off

set "STR=Hello World"

:: World を Universe に置換
set "RESULT=%STR:World=Universe%"
echo %RESULT%
:: → Hello Universe

:: 文字列を削除(空文字に置換)
set "RESULT2=%STR: =%"
echo %RESULT2%
:: → HelloWorld
set置換の特徴

  • 大文字・小文字を区別しない(%STR:world=X% でも置換される)
  • 最初の一致だけでなく、一致するすべての箇所を置換する
  • 正規表現は使えない(リテラル文字列のみ)
  • 検索文字列に = は使えない

2-2. 遅延展開を使った動的置換

for ループや if ブロック内で変数を使って置換するには、遅延展開(!変数:old=new!)が必要です。

@echo off
setlocal enabledelayedexpansion

set "SEARCH=bat"
set "REPLACE=batch"

for %%I in ("bat file" "bat script" "bat tool") do (
    set "ITEM=%%~I"
    :: 遅延展開で動的な検索・置換文字列を使う
    set "RESULT=!ITEM:%SEARCH%=%REPLACE%!"
    echo !RESULT!
)
endlocal

遅延展開の詳細は setlocal enabledelayedexpansion 完全ガイド を参照してください。

2-3. 変数を使って検索・置換文字列を指定する

@echo off
setlocal enabledelayedexpansion

set "STR=2024/01/15 report.csv"
set "OLD=/"
set "NEW=-"

:: !STR:%OLD%=%NEW%! で変数を使って置換
set "RESULT=!STR:%OLD%=%NEW%!"
echo !RESULT!
:: → 2024-01-15 report.csv
endlocal

2-4. 複数パターンを連続置換

@echo off

:: パスのバックスラッシュをスラッシュに変換
set "PATH_STR=C:\work\data\file.txt"
set "RESULT=%PATH_STR:\=/%"
echo %RESULT%
:: → C:/work/data/file.txt

:: スペースをアンダースコアに、ドットをハイフンに(2段階置換)
set "STR=hello world.txt"
set "STEP1=%STR: =_%"
set "FINAL=%STEP1:.=-%"
echo %FINAL%
:: → hello_world-txt

3. for /f でテキストファイルを1行ずつ置換

テキストファイルの内容を置換する場合、for /f で1行ずつ読み込み、置換して別ファイルに書き出す方法が外部ツール不要で実現できます。

@echo off
setlocal enabledelayedexpansion

set "INFILE=C:\work\input.txt"
set "OUTFILE=C:\work\output.txt"
set "OLD=ERROR"
set "NEW=WARN"

:: 出力ファイルを初期化
type nul > "%OUTFILE%"

:: 1行ずつ読み込んで置換し、出力ファイルに追記
for /f "usebackq delims=" %%L in ("%INFILE%") do (
    set "LINE=%%L"
    set "LINE=!LINE:%OLD%=%NEW%!"
    echo !LINE! >> "%OUTFILE%"
)

echo 置換完了: %OUTFILE%
endlocal
for /f の制限:空行・セミコロン行はスキップされる
for /f は 空行をスキップ する仕様です。空行が含まれるファイルでは出力から空行が消えてしまいます。また先頭が ; の行もデフォルトでスキップされます。空行・セミコロン行を保持したい場合は次のセクションの PowerShell 方式を使ってください。

4. PowerShell でファイル内を一括置換

PowerShell の -replace 演算子は正規表現対応で、空行を保持したままファイル全体を1コマンドで置換できます。

4-1. 基本のファイル内置換

@echo off

set "FILE=C:\work\config.txt"
set "OLD=localhost"
set "NEW=192.168.1.100"

:: Get-Content で読み込み、-replace で置換、Set-Content で書き込み
powershell -NoProfile -Command "
    (Get-Content -Path '%FILE%' -Encoding UTF8) -replace '%OLD%', '%NEW%' |
    Set-Content -Path '%FILE%' -Encoding UTF8
"

echo 置換完了: %FILE%

4-2. 正規表現を使った置換

@echo off

set "FILE=C:\work\log.txt"

:: 日付パターン YYYY/MM/DD を YYYY-MM-DD に変換(正規表現・キャプチャグループ)
powershell -NoProfile -Command "
    (Get-Content -Path '%FILE%' -Encoding UTF8) |
    ForEach-Object { $_ -replace '(\d{4})/(\d{2})/(\d{2})', '$1-$2-$3' } |
    Set-Content -Path '%FILE%' -Encoding UTF8
"

:: 行頭の空白・タブを削除
powershell -NoProfile -Command "
    (Get-Content -Path '%FILE%' -Encoding UTF8) |
    ForEach-Object { $_ -replace '^\s+', '' } |
    Set-Content -Path '%FILE%' -Encoding UTF8
"

4-3. 複数パターンを1回のPowerShell呼び出しで一括置換

@echo off

set "FILE=C:\work\data.csv"

:: 複数の置換をまとめて処理(PowerShell 起動を1回に抑えて高速化)
powershell -NoProfile -Command "
    $content = Get-Content -Path '%FILE%' -Encoding UTF8;
    $content = $content -replace 'ERROR', '[ERROR]';
    $content = $content -replace 'WARN',  '[WARN]';
    $content = $content -replace 'INFO',  '[INFO]';
    $content | Set-Content -Path '%FILE%' -Encoding UTF8
"

echo 3パターン置換完了: %FILE%

4-4. 元ファイルを保持して別ファイルに出力

@echo off

set "INFILE=C:\work\original.txt"
set "OUTFILE=C:\work\replaced.txt"

powershell -NoProfile -Command "
    (Get-Content -Path '%INFILE%' -Encoding UTF8) -replace 'old', 'new' |
    Set-Content -Path '%OUTFILE%' -Encoding UTF8
"

echo 出力: %OUTFILE%

PowerShell 連携パターン全般は PowerShellをバッチファイルから呼び出す方法 を参照してください。

5. 落とし穴5選と対策

落とし穴1:検索文字列に = が含まれる場合は set 置換できない

:: NG: = を含む文字列は %var:key=value=X% と解釈が崩れる
set "STR=key=value"
echo %STR:key==% 
:: → 意図しない結果になる(= を検索できない)

:: OK: = を含む場合は PowerShell の -replace を使う
powershell -NoProfile -Command "
    'key=value' -replace 'key=', 'new_key='
"
:: → new_key=value

落とし穴2:遅延展開が有効なとき ! を含む文字列が壊れる

:: setlocal enabledelayedexpansion が有効だと
:: 文字列中の ! が変数の区切りとして展開されてしまう

@echo off
setlocal enabledelayedexpansion
set "STR=Hello!World"

:: NG: ! が展開されて "Hello" だけになる
echo !STR!

:: OK: % 展開なら ! はそのまま出力される
echo %STR%

:: ! を含む文字列の置換は PowerShell を使うのが安全
powershell -NoProfile -Command "'Hello!World' -replace '!', '_'"
endlocal

落とし穴3:set 置換は大文字小文字を区別しない

:: set の文字列置換は常に大文字小文字を区別しない
set "STR=Hello World hello"
set "RESULT=%STR:hello=Hi%"
echo %RESULT%
:: → Hi World Hi  (Hello と hello の両方が置換される)

:: 大文字小文字を区別したい場合は PowerShell の -creplace を使う
powershell -NoProfile -Command "
    'Hello World hello' -creplace 'hello', 'Hi'
"
:: → Hello World Hi  (小文字の hello のみ置換)

落とし穴4:PowerShell の -replace は正規表現なので . や * が特殊文字になる

:: NG: ドット(.)は正規表現で「任意の1文字」を意味する
::     "file.txt" を検索すると "fileXtxt" なども一致してしまう
powershell -NoProfile -Command "'file.txt and fileXtxt' -replace 'file.txt', 'newfile'"
:: → newfile and newfile  (意図しない fileXtxt も置換される)

:: OK: リテラルとして扱うには [regex]::Escape() でエスケープする
powershell -NoProfile -Command "
    $old = [regex]::Escape('file.txt');
    'file.txt and fileXtxt' -replace $old, 'newfile'
"
:: → newfile and fileXtxt  (file.txt のみ置換)

落とし穴5:PowerShell で文字コード指定を忘れると文字化けする

:: NG: -Encoding を省略すると環境によって読み書きの文字コードが変わり文字化けする
powershell -NoProfile -Command "
    (Get-Content 'file.txt') -replace 'old', 'new' | Set-Content 'file.txt'
"

:: OK: UTF-8 ファイルの場合は両方に -Encoding UTF8 を指定
powershell -NoProfile -Command "
    (Get-Content -Path 'file.txt' -Encoding UTF8) -replace 'old', 'new' |
    Set-Content -Path 'file.txt' -Encoding UTF8
"

:: Shift-JIS(ANSI)ファイルの場合は -Encoding Default
powershell -NoProfile -Command "
    (Get-Content -Path 'file.txt' -Encoding Default) -replace 'old', 'new' |
    Set-Content -Path 'file.txt' -Encoding Default
"

6. 実践例3本

実践例1:ログファイルのIPアドレスをマスキング

アクセスログのIPアドレスを *.*.*.* に置換してマスキングするパターンです。

@echo off

set "LOGFILE=C:\logs\access.log"
set "MASKED=C:\logs\access_masked.log"

:: IPアドレスパターン(xxx.xxx.xxx.xxx)を *.*.*.* にマスキング
powershell -NoProfile -Command "
    (Get-Content -Path '%LOGFILE%' -Encoding UTF8) |
    ForEach-Object {
        $_ -replace '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b', '*.*.*.*'
    } |
    Set-Content -Path '%MASKED%' -Encoding UTF8
"

echo マスキング完了: %MASKED%

実践例2:設定ファイルの接続先を環境ごとに一括切り替え

config.ini などの設定ファイルで開発環境の接続先を本番環境に一括置換するパターンです。

@echo off
setlocal

set "CONFIG=C:\app\config.ini"
set "BACKUP=C:\app\config.ini.bak"

:: バックアップを作成してから置換
copy /y "%CONFIG%" "%BACKUP%" >nul

:: 開発環境 → 本番環境に切り替え
powershell -NoProfile -Command "
    $content = Get-Content -Path '%CONFIG%' -Encoding UTF8;
    $content = $content -replace 'HOST=dev\.example\.com', 'HOST=prod.example.com';
    $content = $content -replace 'PORT=8080', 'PORT=443';
    $content = $content -replace 'DEBUG=true', 'DEBUG=false';
    $content | Set-Content -Path '%CONFIG%' -Encoding UTF8
"

echo 設定切り替え完了。元ファイルのバックアップ: %BACKUP%
endlocal

実践例3:CSVのフィールドを正規化してサニタイズ

外部から受け取ったCSVのフィールドに含まれる改行コード(
)や連続スペースを除去するパターンです。

@echo off

set "INFILE=C:\data\raw.csv"
set "OUTFILE=C:\data\clean.csv"

:: CR(\r)を除去し、連続スペースを1つに正規化
powershell -NoProfile -Command "
    (Get-Content -Path '%INFILE%' -Encoding UTF8) |
    ForEach-Object {
        $line = $_ -replace '\r', '';
        $line = $line -replace ' {2,}', ' ';
        $line
    } |
    Set-Content -Path '%OUTFILE%' -Encoding UTF8
"

echo サニタイズ完了: %OUTFILE%

まとめ:使い分け早見表

やりたいこと 方法 ポイント
変数内の文字列を置換 %変数:old=new% シンプル・外部ツール不要
ループ内で動的に置換 !変数:old=new!(遅延展開) for/if 内で必須
テキストファイルを1行ずつ置換 for /f + set置換 外部ツール不要・空行は消える
ファイル内を一括置換 PowerShell Get-Content -replace 空行保持・-Encoding 指定必須
正規表現で置換 PowerShell -replace パターンマッチ対応
大文字小文字を区別して置換 PowerShell -creplace 区別あり版
= を含む文字列を置換 PowerShell -replace set置換では不可

FINDSTRコマンドの使い方完全ガイド も合わせて参照してください。

FAQ

Q. %変数:old=new% で置換できません。変数が空になります。
A. 主な原因は①変数が未定義(echo %変数名% で確認)、②検索文字列に = が含まれる(PowerShell を使用)、③for/if ブロック内で % 展開を使っている(!変数:old=new! に変更)の3つです。
Q. for /f でファイルを置換したら空行が消えました。
A. for /f は空行をスキップする仕様です。空行を保持したい場合は PowerShell の (Get-Content ...) -replace 'old', 'new' | Set-Content ... を使ってください。
Q. PowerShell の -replace で . や * がうまく動きません。
A. -replace は正規表現を使うため、.(任意の1文字)・*(0回以上)などが特殊文字として解釈されます。リテラルとして扱うには [regex]::Escape('検索文字列') でエスケープしてください。
Q. PowerShell でファイルを置換したら文字化けしました。
A. -Encoding の指定が必要です。UTF-8ファイルなら -Encoding UTF8、Shift-JIS(ANSI)なら -Encoding DefaultGet-ContentSet-Content の両方に付けてください。
Q. 大文字小文字を区別して置換したい。
A. PowerShell の -creplace 演算子(case-sensitive replace)を使ってください。'Hello World hello' -creplace 'hello', 'Hi' は小文字の hello のみ置換し、Hello はそのままになります。
Q. 引数で受け取ったファイルパスを対象に置換したい。
A. set "FILE=%~1" でパスを変数に受け取り、PowerShell コマンドに '%FILE%' として渡します。引数の受け取り方の詳細は バッチファイルで引数を渡す方法完全ガイド を参照してください。