バッチファイルで「ファイル名から拡張子を除いた部分だけ取り出したい」「日付文字列から年・月・日を分けたい」「CSVの特定フィールドを抽出したい」と思ったことはありませんか?
バッチファイルには %変数名:~開始位置,文字数% という構文があり、文字列の任意の部分を切り出せます。本記事ではこの基本構文から、FOR /F による区切り文字での分割、文字列の長さ取得、空白のトリム、そして遅延展開が必要な場面まで、実務でよく使うパターンをすべて解説します。
この記事でわかること
%変数名:~開始,長さ%構文の使い方(先頭・末尾・マイナスインデックス)- FOR /F を使った区切り文字での分割(CSV・メールアドレス・パス)
- 文字列の長さをバッチファイルで取得する方法
- 先頭・末尾の空白を除去するトリム処理
- 遅延展開(enabledelayedexpansion)が必要な場面と注意点
- よくあるエラーと対処法
基本構文:位置と文字数で切り出す
バッチファイルの文字列切り出しは set コマンドのサブストリング機能を使います。
%変数名:~開始位置,文字数%
| パラメータ | 説明 | 省略時の動作 |
|---|---|---|
| 開始位置 | 0から始まるインデックス(先頭=0) | — |
| 文字数 | 切り出す文字数 | 省略すると末尾まで取得 |
先頭から切り出す
@echo off set str=Hello, World! :: 先頭から5文字切り出す set result=%str:~0,5% echo %result% :: 出力: Hello
位置を指定して切り出す
@echo off set str=Hello, World! :: 7文字目から5文字切り出す(インデックスは0始まり) set result=%str:~7,5% echo %result% :: 出力: World
指定位置から末尾まで取得
文字数を省略すると、開始位置から文字列の末尾まで取得できます。
@echo off set str=Hello, World! :: 7文字目から末尾まで set result=%str:~7% echo %result% :: 出力: World!
末尾から切り出す(マイナスインデックス)
開始位置にマイナスの値を指定すると、文字列の末尾からの位置を指定できます。
@echo off set str=Hello, World! :: 末尾から6文字取得 set result=%str:~-6% echo %result% :: 出力: orld! :: 末尾から6文字目の位置から3文字取得 set result=%str:~-6,3% echo %result% :: 出力: orl
マイナスインデックスの注意点
ただし
%str:~-6% は末尾6文字を返します(Pythonの str[-6:] と同じ感覚)。ただし
%str:~-6,-2% のような「末尾から末尾まで」の指定はバッチではできません。よく使う切り出しパターン
日付から年・月・日を取り出す
%DATE% 変数から年・月・日を個別に取り出せます(OS設定によってフォーマットが異なる点に注意)。
@echo off :: %DATE% の形式: 2026/03/18 (火) など(環境依存) set today=%DATE% :: yyyy/mm/dd 形式の場合 set year=%today:~0,4% set month=%today:~5,2% set day=%today:~8,2% echo 年: %year% 月: %month% 日: %day% :: 出力: 年: 2026 月: 03 日: 18 :: yyyymmdd 形式のファイル名に使う set datestamp=%year%%month%%day% echo output_%datestamp%.log :: 出力: output_20260318.log
%DATE%のフォーマットは環境依存
Windows の地域設定によって形式が変わります(
Windows の地域設定によって形式が変わります(
yyyy/mm/dd、mm/dd/yyyy など)。スクリプトを他の環境でも使う場合は wmic os get LocalDateTime で固定フォーマットを取得することを推奨します。時刻から時・分・秒を取り出す
@echo off :: %TIME% の形式: 14:30:05.12 set now=%TIME% set hour=%now:~0,2% set minute=%now:~3,2% set second=%now:~6,2% echo %hour%時%minute%分%second%秒 :: 出力: 14時30分05秒
ファイルパスからファイル名・拡張子を取り出す
FOR 文の変数修飾子を使う方法が最も確実です。
@echo off
set filepath=C:\Users\admin\Documents\report.xlsx
:: FOR文でファイル名・拡張子を取得
for %%f in ("%filepath%") do set filename=%%~nxf
echo ファイル名: %filename%
:: 出力: report.xlsx
:: 拡張子なしのファイル名
for %%f in ("%filepath%") do set name=%%~nf
echo 名前: %name%
:: 出力: report
:: 拡張子のみ
for %%f in ("%filepath%") do set ext=%%~xf
echo 拡張子: %ext%
:: 出力: .xlsx
%%~nxf などの修飾子まとめ
%%~nf: 拡張子なしのファイル名 / %%~xf: 拡張子 / %%~nxf: ファイル名+拡張子 / %%~dpf: ドライブ+パス / %%~ff: フルパスFOR /F で区切り文字による分割
FOR /F の delims(区切り文字)と tokens(取得位置)を使うと、特定の文字で分割した各フィールドを取得できます。
カンマ区切りで分割(CSV形式)
@echo off
set line=田中太郎,25,東京都
for /f "tokens=1,2,3 delims=," %%a in ("%line%") do (
echo 名前: %%a
echo 年齢: %%b
echo 住所: %%c
)
:: 出力:
:: 名前: 田中太郎
:: 年齢: 25
:: 住所: 東京都
メールアドレスを@で分割
@echo off
set addr=user@example.com
:: @より前(ユーザー名)
for /f "tokens=1 delims=@" %%a in ("%addr%") do set user=%%a
echo ユーザー名: %user%
:: 出力: user
:: @より後(ドメイン)
for /f "tokens=2 delims=@" %%a in ("%addr%") do set domain=%%a
echo ドメイン: %domain%
:: 出力: example.com
複数の区切り文字を同時に指定
@echo off
set str=2026-03-18_report
:: - と _ 両方を区切り文字にする
for /f "tokens=1,2,3,4 delims=-_" %%a in ("%str%") do (
echo 年: %%a
echo 月: %%b
echo 日: %%c
echo 名称: %%d
)
FOR /F の tokens 上限に注意
tokensで指定できる変数は最大26個(%%a〜%%z)です。また
tokensで指定できる変数は最大26個(%%a〜%%z)です。また
delims= を省略するとスペース・タブが区切り文字になります。先頭のスペースを含む値を取得したい場合は "tokens=* delims=" を使います。文字列の長さを取得する
バッチファイルには文字列長を返す組み込み関数がありません。FOR /L ループでカウントする方法が定番です。
@echo off setlocal enabledelayedexpansion set str=Hello, World! set len=0 :loop if "!str:~%len%,1!" NEQ "" ( set /a len+=1 goto loop ) echo 文字列の長さ: %len% :: 出力: 文字列の長さ: 13
PowerShell を使う方が簡単
文字列長の取得は PowerShell を呼ぶ方がシンプルです:
文字列長の取得は PowerShell を呼ぶ方がシンプルです:
for /f %%a in ('powershell -command "\"Hello\".Length"') do set len=%%a空白のトリム(先頭・末尾のスペース除去)
バッチには trim 関数がないため、FOR /F を使って空白をトリムします。
先頭・末尾の空白を除去
@echo off
set str= Hello, World!
:: FOR /Fで先頭の空白を除去(tokens=* delims= はスペース区切りを無視)
for /f "tokens=* delims= " %%a in ("%str%") do set trimmed=%%a
echo [%trimmed%]
:: 出力: [Hello, World! ] ← 先頭のみ除去
:: 末尾の空白は除去が複雑なため、PowerShell推奨
for /f "delims=" %%a in ('powershell -command "'' Hello ''.Trim()"') do set trimmed=%%a
echo [%trimmed%]
:: 出力: [Hello]
文字列の置換で切り出す
不要な部分を空文字で置換することで、実質的な切り出しができます。
@echo off set str=ABC-DEF-GHI :: "ABC-" を削除して "DEF-GHI" を取得 set result=%str:ABC-=% echo %result% :: 出力: DEF-GHI :: 拡張子を除去(置換で擬似的なパス処理) set filename=report.xlsx set noext=%filename:.xlsx=% echo %noext% :: 出力: report
遅延展開が必要な場面
ループ内で切り出した文字列を使う場合は、遅延展開(enabledelayedexpansion)が必要です。
ループ内での動的な切り出し(遅延展開あり)
@echo off setlocal enabledelayedexpansion set str=ABCDEFGHIJ :: 1文字ずつ切り出して表示 for /l %%i in (0,1,9) do ( set char=!str:~%%i,1! echo %%i文字目: !char! ) :: 出力: :: 0文字目: A :: 1文字目: B :: ... 以下略
遅延展開なし(NG例)
@echo off :: NG: 遅延展開なし set str=ABCDEFGHIJ for /l %%i in (0,1,9) do ( set char=%str:~%%i,1% echo %char% ) :: 出力: (空白が10回) ← %%iがループ前に展開されてしまう
遅延展開のポイント
- ループの内側で変数の値を参照するには
!変数名!を使う %変数名%はスクリプトのパース時(実行前)に展開されてしまうsetlocal enabledelayedexpansionは必ずスクリプトの先頭で宣言する
実用パターン集
ログファイル名に日時スタンプを付ける
@echo off
setlocal
:: wmic で確実な日時フォーマット取得
for /f "skip=1 tokens=1" %%a in ('wmic os get localdatetime') do set dt=%%a
:: dt = 20260318143005.000000+540 の形式
set datestamp=%dt:~0,8%
set timestamp=%dt:~8,6%
set logfile=app_%datestamp%_%timestamp%.log
echo %logfile%
:: 出力: app_20260318_143005.log
URLからパスだけを取り出す
@echo off
set url=https://example.com/path/to/page
:: https:// を除去
set path=%url:https://=%
:: path = example.com/path/to/page
:: 最初の / 以降を取得(FOR /F 活用)
for /f "tokens=2 delims=/" %%a in ("%path%") do set part=%%a
echo %part%
:: 出力: path
テキストから特定フォーマットを抽出
@echo off
setlocal enabledelayedexpansion
:: "VERSION=1.2.3" 形式からバージョン番号だけ取得
set line=VERSION=1.2.3
:: = 以降を取得
for /f "tokens=2 delims==" %%a in ("%line%") do set version=%%a
echo バージョン: %version%
:: 出力: バージョン: 1.2.3
:: メジャーバージョンのみ
set major=%version:~0,1%
echo メジャーバージョン: %major%
:: 出力: メジャーバージョン: 1
切り出し構文まとめ
| やりたいこと | 構文 | 例 |
|---|---|---|
| 先頭からN文字 | %var:~0,N% |
%str:~0,5% → 先頭5文字 |
| M文字目からN文字 | %var:~M,N% |
%str:~7,5% → 7文字目から5文字 |
| M文字目から末尾まで | %var:~M% |
%str:~7% → 7文字目以降すべて |
| 末尾からN文字 | %var:~-N% |
%str:~-5% → 末尾5文字 |
| 区切り文字で分割 | for /f "tokens=N delims=X" |
カンマ・スペース・@など |
| 特定文字列を除去 | %var:文字列=% |
%str:ABC-=% → ABC-を削除 |
| ループ内の動的切り出し | !var:~%%i,1! |
遅延展開必須 |
よくあるエラーと対処法
切り出しても空文字が返ってくる
インデックスが文字列の範囲外の場合、空文字が返ります。
@echo off set str=Hello :: 長さ5の文字列で10文字目を指定 set result=%str:~10,1% echo [%result%] :: 出力: [] ← 空文字(エラーにはならない)
ループ内で値が変わらない(遅延展開忘れ)
@echo off :: NG: 遅延展開なし → %%i の展開タイミングが間違い set str=ABCDEF for /l %%i in (0,1,5) do ( echo %str:~%%i,1% ← これは空または文字化けする ) :: OK: 遅延展開あり setlocal enabledelayedexpansion set str=ABCDEF for /l %%i in (0,1,5) do ( echo !str:~%%i,1! )
最も多いミス:遅延展開の忘れ
ループ内で
ループ内で
%変数%:~%%i,1% を使っても動きません。setlocal enabledelayedexpansion を宣言して !変数!:~%%i,1! を使ってください。スペースを含む文字列が途切れる
@echo off
set str=Hello World
:: NG: FOR /F はデフォルトでスペースが区切り文字になる
for /f %%a in ("%str%") do echo %%a
:: 出力: Hello ← World が切り捨てられる
:: OK: delims= を空にしてスペースを区切り文字から除外
for /f "delims=" %%a in ("%str%") do echo %%a
:: 出力: Hello World
特殊文字(!、^、&)を含む文字列
@echo off setlocal enabledelayedexpansion :: ! は遅延展開で特殊文字になるため ^ でエスケープ set str=Hello^!World echo %str% :: 出力: Hello!World :: 切り出しの際も問題なし set result=!str:~0,5! echo %result% :: 出力: Hello
よくある質問
Q. %変数:~0,5% と %変数:~0,-5% の違いは何ですか?
A.
%var:~0,5% は先頭から5文字を取得します。一方 %var:~0,-5% は先頭から末尾5文字を除いた部分を返します。例えば “ABCDEFGHIJ”(10文字)なら :~0,-5% は “ABCDE”(末尾5文字の “FGHIJ” を除いた部分)を返します。Q. 日本語(全角)文字列の切り出しはできますか?
A. バッチファイルの
:~ 構文はバイト単位ではなく文字数単位で動作しますが、コードページの影響を受けます。日本語を含む場合は chcp 65001(UTF-8)に設定して動作確認してください。PowerShell を使う方が安全です。Q. FOR /F で取得した値が空になることがあります。なぜですか?
A. 主な原因は3つです。①変数に値がセットされていない(タイポ等)、②区切り文字の設定ミス(
delims=, なのに区切り文字が違う)、③スペースを含む値で delims= の指定漏れ。echo [%変数%] でブラケット付きでデバッグ表示すると原因が特定しやすいです。Q. Python の str[2:5] のようなスライス記法はバッチでも使えますか?
A. 直接の対応はありませんが、
%var:~2,3%(2文字目から3文字)が近い動作をします。末尾を除外する str[:-2] は %var:~0,-2% で対応できます。ただしバッチのインデックスは0始まりで Python と同じです。Q. 大文字・小文字の変換はできますか?
A.
%var:lower=upper% のような直接変換はできません。PowerShell を呼び出す方法が現実的です:for /f %%a in ('powershell -command "''hello''.ToUpper()"') do set upper=%%a。これで “HELLO” が取得できます。まとめ
バッチファイルの文字列切り出しポイント
%var:~開始,長さ%が基本構文(インデックスは0始まり)- マイナスインデックスで末尾からの位置指定が可能
- 区切り文字での分割は
FOR /F "tokens=N delims=X" - ループ内での動的切り出しには 遅延展開(
!var:~%%i,1!)が必須 - 文字列長の取得・空白トリムなど高度な処理は PowerShell 活用が現実的
