Windowsコマンドプロンプトでテキストファイル内の文字列を簡単に置き換える方法

Windowsのコマンドプロンプト(cmd.exe)からテキストファイルの文字列を置き換えるには、PowerShellを呼び出す方法が便利です。cmdの構文とPowerShellの構文は別物なので、入力する画面を区別してください。本記事では、まず文字列だけで置換を試し、次に元ファイルを上書きせず別ファイルへ保存する方法を説明します。

対象は自分が編集権限を持つテキストファイルです。重要なファイルは別の場所へバックアップし、使用中のアプリを閉じてください。通常は管理者として起動する必要はありません。設定ファイルやソースコードは、変更後に利用するアプリ側でも確認します。

目次

コマンドプロンプトとPowerShellを区別する

スタートメニューで「コマンド プロンプト」を検索して開きます。cmdで現在のフォルダーを表示するのは cd、移動は次の例です。スペースを含むパスは二重引用符で囲み、ドライブも変更する場合は /d を付けます。

cd
cd /d "C:\work"

以降、「PowerShellで実行」と書いた例はPowerShellの画面へ入力します。Windows PowerShell 5.1の実行ファイルは powershell.exe、別途導入したPowerShell 7は pwsh.exe です。まず次の読み取り専用の例をcmdから実行すると、文字列の置換結果だけを表示できます。ファイルは変更しません。

powershell.exe -NoProfile -Command "'foo FOO foo'.Replace('foo', 'bar')"

表示される文字列は bar FOO bar です。.Replace() のこの使い方は文字どおりの置換で、大文字・小文字を区別します。foo が単語の一部に含まれていても置換するため、単語限定の変更とは異なります。

単純な置換と正規表現の使い分け

PowerShellの -replace は正規表現を使い、既定では大文字・小文字を区別しません。例えば検索文字列の . は任意の1文字として扱われます。単なる文字列の置換なら .Replace()、パターンに一致する範囲を置き換えるなら -replace を選びます。

'foo FOO'.Replace('foo', 'bar')  # bar FOO
'foo FOO' -replace 'foo', 'bar'  # bar bar
'foo FOO' -creplace 'foo', 'bar' # bar FOO
'a.b axb'.Replace('a.b', 'X')   # X axb

正規表現の置換先では $1 などがキャプチャの参照になります。検索語のエスケープだけで、置換先まで文字どおりになるわけではありません。ユーザー入力や記号を含む任意の文字列には、安易に -replace を使わないでください。

UTF-8ファイルを別名で保存する安全側の例

次のスクリプトでは C:\work\example.txt のようなドライブ名付き絶対パスを指定します。UNC共有パスや相対パスは対象外です。入力がUTF-8であると分かっている、小~中規模のテキストファイル専用です。UTF-8のBOMの有無を維持し、テキスト全体を読み取ることで、置換対象に含まれない改行や末尾改行をそのまま扱います。Shift_JIS、UTF-16、文字コード不明のファイルには使わないでください。UTF-8として不正なバイト列を検出した場合は停止しますが、文字コードを自動判定する機能ではありません。

以下を C:\work\replace-utf8.ps1 として保存します。例のスクリプト本体はASCII文字だけです。日本語のコメントや引数の既定値を追記してWindows PowerShell 5.1で使う場合は、スクリプト自体をUTF-8 BOM付きで保存するなど、5.1側が正しく読める形式にしてください。

param(
    [Parameter(Mandatory=$true)][string]$InputPath,
    [Parameter(Mandatory=$true)][string]$OutputPath,
    [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$Old,
    [Parameter(Mandatory=$true)][AllowEmptyString()][string]$New
)
$ErrorActionPreference = 'Stop'
try {
    if ($InputPath -notmatch '^[A-Za-z]:[\\/]' -or
        $OutputPath -notmatch '^[A-Za-z]:[\\/]') {
        throw 'Use drive-qualified absolute paths, such as C:\work\file.txt.'
    }
    $src = [IO.Path]::GetFullPath($InputPath)
    $dst = [IO.Path]::GetFullPath($OutputPath)
    if ([string]::Equals($src, $dst, [StringComparison]::OrdinalIgnoreCase)) {
        throw 'Input and output must be different.'
    }
    $bytes = [IO.File]::ReadAllBytes($src)
    $hasBom = $bytes.Length -ge 3 -and $bytes[0] -eq 239 -and
              $bytes[1] -eq 187 -and $bytes[2] -eq 191
    $offset = 0
    if ($hasBom) { $offset = 3 }
    $utf8 = New-Object System.Text.UTF8Encoding($false, $true)
    $text = $utf8.GetString($bytes, $offset, $bytes.Length - $offset)
    $result = $text.Replace($Old, $New)
    $data = $utf8.GetBytes($result)
    $stream = [IO.File]::Open($dst, [IO.FileMode]::CreateNew,
        [IO.FileAccess]::Write, [IO.FileShare]::None)
    try {
        if ($hasBom) { $stream.Write($bytes, 0, 3) }
        $stream.Write($data, 0, $data.Length)
    }
    finally { $stream.Dispose() }
    Write-Output ('Created: ' + $dst)
}
catch {
    [Console]::Error.WriteLine($_.Exception.Message)
    exit 1
}

cmdからは次のように呼び出します。事前に C:\work を用意し、UTF-8の example.txt を置いてください。出力先 example.replaced.txt が既にある場合は上書きせずエラーになります。

powershell.exe -NoProfile -File "C:\work\replace-utf8.ps1" -InputPath "C:\work\example.txt" -OutputPath "C:\work\example.replaced.txt" -Old "foo" -New "bar"

元ファイルは書き換えません。ただしディスク容量不足などで書き込みに失敗した場合、出力先に不完全なファイルが残ることがあります。成功表示と内容を確認するまでは、出力ファイルを採用しないでください。この例は全内容をメモリへ読み込むため、巨大ログ用ではありません。出力のアクセス権・作成日時なども元ファイルと同一になる保証はありません。

スクリプトの実行が組織のポリシーで禁止されている場合は、管理者に承認済みの実行方法を確認してください。置換のために実行ポリシーを一律で無効化したり、管理者権限で強行したりする必要はありません。

バッチファイルで同じ処理を呼び出す

上のスクリプトと入力ファイルを同じフォルダーへ置き、次を replace.bat として保存する例です。%~dp0 はバッチ自身のある場所を指すので、ダブルクリック時の作業フォルダーに依存しません。出力は前節と同じく新規ファイルに限定します。

@echo off
powershell.exe -NoProfile -File "%~dp0replace-utf8.ps1" -InputPath "%~dp0example.txt" -OutputPath "%~dp0example.replaced.txt" -Old "foo" -New "bar"
if errorlevel 1 (
  echo Replacement failed. Check the error and output file.
  exit /b 1
)
echo Review example.replaced.txt before using it.
exit /b 0

これは固定の foo → bar 用の例です。cmdには %、!、& などの特殊な解釈があるため、任意の文字列を単純連結してコマンドへ渡す汎用バッチにはしないでください。複雑な置換条件はレビュー可能なPowerShellスクリプト内で管理します。

複数ファイルは対象を確認してから別フォルダーへ出力

まずPowerShellで対象の一覧を確認します。次の例は指定フォルダー直下の .txt だけで、サブフォルダーを再帰処理しません。作業用にコピーしたファイルを使い、元の場所とは別の新しい出力フォルダーを用意します。

Get-ChildItem -LiteralPath 'C:\work\input' -Filter '*.txt' -File | Select-Object FullName, Length

対象と文字コードを確認した後、PowerShellで次を実行します。C:\work\output は先に作成した空のフォルダーを指定してください。1件でも失敗したら停止しますが、それ以前に作成された出力は残ります。一括処理全体が自動で元に戻る仕組みではありません。

$ErrorActionPreference = 'Stop'
$files = Get-ChildItem -LiteralPath 'C:\work\input' -Filter '*.txt' -File
foreach ($file in $files) {
    $out = Join-Path 'C:\work\output' $file.Name
    & powershell.exe -NoProfile -File 'C:\work\replace-utf8.ps1' `
        -InputPath $file.FullName -OutputPath $out -Old 'foo' -New 'bar'
    if ($LASTEXITCODE -ne 0) { throw ('Failed: ' + $file.FullName) }
}

文字コード・BOM・改行を確認する

Get-Content -Encoding Default は文字コードを判定するコマンドではありません。Windows PowerShell 5.1ではシステムのANSIコードページを指定するもので、UTF-8やShift_JISを自動的に見分ける機能ではありません。BOMのないファイルは、バイト列だけで文字コードを一意に判断できない場合があります。作成元アプリの仕様や、文字コードを明示できるエディターで確認してください。

Windows PowerShell 5.1とPowerShell 7では既定の出力エンコーディングが異なります。5.1の Set-Content の既定値や > の出力形式、7のUTF-8 BOMなしという既定値を混同しないでください。単に Get-Content の行配列を Set-Content へ渡す例では、改行や末尾改行も変わり得ます。

UTF-8とUTF-16はいずれもUnicodeを表せるエンコーディングであり、「UTF-16の方が多くの文字に対応する」という区別ではありません。Shift_JISには表せない文字があり、変換時に情報を失う可能性があります。全ファイルを無条件にUTF-8へ統一するのではなく、読み手のアプリが要求する文字コード・BOM・改行形式に合わせます。

Git Bashなどでsedを使う場合

sed はcmdの標準内部コマンドではありません。利用可能なGNU sedが入っているGit Bashなどのシェルで実行します。以下はBash側の例で、cmdへそのまま貼り付けるための構文ではありません。まず画面へ結果を表示して確認します。

sed 's/foo/bar/g' example.txt

g は各行の一致箇所をすべて置換する指定です。検索側は正規表現、置換側の & などは特殊な意味を持ちます。内容を確認し、別途バックアップを取った作業用コピーで、GNU sedのバックアップ付き編集を行う場合は次の形式です。既存の example.txt.bak があるなら先に別の場所へ保存し、バックアップを上書きしないようにします。

sed -i.bak 's/foo/bar/g' example.txt

このコマンドは入力ファイルを変更します。PowerShellの別名出力例とは挙動が違います。BOMや文字コードを自動で適切な形式へ変換するものではなく、UTF-16や未知のエンコーディングへの適用は避けてください。利用するsedの実装によってオプションも異なるため、GNU以外では説明書を確認します。

ログ・ソースコード・メールアドレスの置換で注意すること

IPアドレスを置き換えても匿名化の完了ではない

正規表現の . は \. と書いて文字どおりのドットにします。単純な部分一致では、長い文字列の途中まで変えてしまうこともあります。次はPowerShellのメモリ上だけで動く、限定的な例です。ログの形式に合わせた検証が必要で、他のIPアドレス・ユーザー名・トークンなども含めた完全な匿名化は保証しません。

'src=192.168.1.100 dst=192.168.1.1000' -replace '(?<![0-9.])192\.168\.1\.100(?![0-9.])', '[IP]'

変数名の一括変更はIDEのリファクタリングを優先

ソースコードに対する .Replace() は、コメント・文字列リテラル・別の識別子の一部まで変更します。変数の参照範囲を考慮する名前変更にはIDEのリファクタリングを使い、差分・ビルド・テストを確認してください。単純なテキスト置換を行う場合も、バージョン管理下の作業用コピーで対象を限定します。

複数の置換は順番と連鎖を明示する

置換規則の順番によって結果は変わります。次の例はPowerShellで foo → bar → baz の順に処理するため、最初の foo も最終的には baz になります。同時置換ではありません。順序が重要なときに通常のハッシュテーブルの列挙順へ依存しないでください。

$text = 'foo bar'
$text = $text.Replace('foo', 'bar')
$text = $text.Replace('bar', 'baz')
$text # baz baz

メールアドレスのドメイン変更はローカル部を残す

アドレス全体を固定の [email protected] に置換すると、異なる利用者が同じ文字列になってしまいます。次は「1行がASCIIの簡単なメールアドレス1件」という限定された入力を想定し、ドメインだけを変更するPowerShellの例です。一般の文章・CSV・引用符付きアドレスなどを完全に解析する正規表現ではありません。

'[email protected]' -replace '^([A-Za-z0-9._%+-]+)@old-domain\.com$', '${1}@new-domain.com'

結果は [email protected] です。置換先を単一引用符で囲んでPowerShellの変数展開を避け、キャプチャしたローカル部を残しています。実際のメールアカウントや配送先が移行されるわけではありません。置換後のアドレスが有効かどうかは別途確認してください。

実行後の確認とトラブル対処

出力の件数、置換箇所、変更しないはずの行、改行・BOM・日本語の表示を差分ツールやエディターで確認します。設定ファイルは構文チェック、ソースコードはテストも行い、問題がないことを確かめてから採用します。置換対象が存在しない場合でも出力ファイルが作られるため、「Created」の表示だけで意図した置換が済んだとは判断できません。

「ファイルが見つからない」は入力パス、「既に存在する」は出力名、「アクセスが拒否された」は権限・使用中のアプリ・保存先を確認します。文字化けした場合は元ファイルに戻り、推測した文字コードで何度も上書きしないでください。書き込み途中で失敗した出力は使用せず、原因を解消して別の出力名で再試行します。

まとめ

cmdからの文字列置換は、PowerShellを明示的に呼び出すと整理できます。文字どおりの置換と正規表現を区別し、既知の文字コードで読み書きし、まず別ファイルへ出力することが基本です。複数ファイルや自動化へ広げる前に、1つの作業用コピーで差分と利用先の動作を確認してください。

参考資料

Microsoft Learn:String.Replace

Microsoft Learn:cmdからPowerShellを実行する引数

Microsoft Learn:比較・置換演算子

Microsoft Learn:文字エンコーディング

Microsoft Learn:UTF8Encodingのエラー検出とBOM

Microsoft Learn:FileMode.CreateNew

Microsoft Learn:実行ポリシー

GNU sed:コマンドラインオプション

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次