JavaScriptを有効にしてください

Powershellでファイル名に連番を振ってリネームする

 ·   6 min read

はじめに

Poweshellを使って、フォルダ内のファイルに連番を振ってリネームする方法をまとめた。現在のファイル名の順に連番を振る場合、以下を実行する(拡張子は適宜変更のこと)。

1
2
ls | sort Name | 
% {$i = 1} { $NewName = "{0:000}.txt" -f $i; mv $_.Name $NewName; $i++ }

もしくは以下を実行しても同じ結果になる。

1
ls | sort Name | % {$i = 1} {mv $_.Name ("{0:000}.txt" -f $i++)}

後者のコードは少し複雑なため、本記事では前者を解説する。

実行手順

あるフォルダに以下のファイルが存在するとする(拡張子はtxt以外でも良い)。

aaa.txt
bbb.txt
ccc.txt

これらのファイルの順番を変更せずに、以下のように連番を振ってリネームしたい。

001.txt <- aaa.txtからリネーム
002.txt <- bbb.txtからリネーム
003.txt <- ccc.txtからリネーム

Powershellを使ってリネームする場合、以下の手順で行う。
ただし、失敗した場合に備えて、あらかじめオリジナルのフォルダをバックアップするか、数個のファイルで動作を検証してから実行されたい。

  1. フォルダの何もない場所でShiftキーを押しながら右クリックし、「PowerShell ウィンドウをここで開く(S)」を押す。
  2. PowerShellが起動したら、以下のどちらかを実行する(拡張子がtxt以外の場合は適宜変更する)。
1
2
ls | sort Name | 
% {$i = 1} { $NewName = "{0:000}.txt" -f $i; mv $_.Name $NewName; $i++ }
1
ls | sort Name | % {$i = 1} {mv $_.Name ("{0:000}.txt" -f $i++)}

解説

前者のコマンドレットについて解説する(PowerShellのコマンドは、コマンドレットと呼ばれる)。なお、疑似コードにすると以下のようになる。

ファイルの一覧を取得
ファイル一覧を名前の順にソートする
i = 1
for (各ファイルについてループ)
{
    新しいファイル名 = {i}.txt
    ファイル名を「新しいファイル名」に変更
    i = i+1
}

エイリアス(別名)

コマンドレットは基本的に「動詞+名詞」の組み合わせであるが、一部のコマンドレットにはLinuxシェルなどと同じ名前のエイリアス(別名)が付けられている。

1
2
ls | sort Name | 
% {$i = 1} { $NewName = "{0:000}.txt" -f $i; mv $_.Name $NewName; $i++ }

というコマンドレットには、以下のエイリアスが含まれている。

エイリアス コマンドレット 備考
ls Get-ChildItem ディレクトリ情報の取得
sort Sort-Object ソート
% ForEach-Object 配列のオブジェクトを一つずつ処理
mv Move-Item ファイルの移動・リネーム

パイプライン

あるコマンドレットの実行結果を別のコマンドレットで処理したい場合、パイプライン|でコマンドレット同士をつなぐ。

lsを実行すると、実行フォルダにあるファイル・フォルダのリストが返される。
それをsort Nameで名前の順に並べ替える。
さらに、mvで名前を変更する。

変数

PowerShellでは、文字列の先頭に$を付けると変数になる。
ここでは$i = 1で変数を宣言し、初期値1を代入している。
もしファイル名を0始まりにしたい場合は$i = 0とする。
また、$NewNameには文字列が格納される。

$_は少し特殊であり、前のパイプラインから渡されたオブジェクトを表す変数である。
コマンドレットの先頭から追っていくと、最初のlsはファイルオブジェクトの配列を返す。
sort Nameは単にソートするだけであるので、やはりファイルオブジェクトの配列を返す。
2番目のパイプラインの後ろではループ処理が入っている(後述)ので、$_にはファイルオブジェクトが格納されている。
また、$_.Nameはファイル名(言い換えるとファイルオブジェクトのNameプロパティ)である。

ForEach-Objectによるループ処理

%ForEach-Objectのエイリアス)では、配列の要素を一個ずつ取り出して処理することができる。

1
% {$i = 1} { $NewName = "{0:000}.txt" -f $i ; mv $_.Name $NewName; $i++ }

上記の例では、{$i = 1}が最初に1回だけ実行され、
{ $NewName = "{0:000}.txt" -f $i ; mv $_.Name $NewName; $i++ }
は配列の長さ(ここではファイルの数)と同じ回数実行される。

%では、以下のオプションでループの前および後に処理を追加できる。

  • -Begin: ループの前に実行する処理
  • -Process: ループ内で実行する処理
  • -End: ループ後に実行する処理

追加する処理は{ }で囲む(囲まれた単位をスクリプトブロックと呼ぶ)。

最初にAと表示し、ループ回数(3回)だけBと表示し、最後にCと表示する。

1
2
3
4
5
6
PS > 1..3 | % -Begin {"A"} -Process {"B"} -End {"C"}
A
B
B
B
C

ここで1..3は数値1, 2, 3の配列である。なお、-Begin, -Process, -Endオプションを指定しない場合、以下のように解釈される。

スクリプトブロックが、

  • 1個の場合:-Process
  • 2個の場合:1個目は-Begin, 2個目は-Process
  • 3個以上の場合:1個目は-Begin, 最後は-End, それ以外は-Process

スクリプトブロックが4個の例 : 最初にAと表示し、ループ回数(3回)だけB, Cの順に表示し、最後にDと表示する。

1
2
3
4
5
6
7
8
9
PS > 1..3 | % {"A"} {"B"} {"C"} {"D"}
A
B
C
B
C
B
C
D

数値→文字列変換のフォーマット

$iは数値であるので、これをファイル名にするため、以下で文字列に変換する。

1
$NewName = "{0:000}.txt" -f $i

{0:000}の最初の0は、複数の変数を文字列に変換したいときに、何番目の変数を変換するかを指定する。

2つの変数を文字列に変換する例

1
2
3
4
PS > $i = 5
PS > $j = 10
PS > "{0:000}_{1:000}.txt" -f $i, $j
005_010.txt

また、{0:000}:以降で数値の書式を指定しており、000は先頭を0埋めした3桁の整数を意味する。
なお、"{0:000}.txt" -f $iは以下と等価である。

  • "{0:D3}.txt" -f $i
  • $i.ToString("000")+".txt"

ファイルの名前を変更する

mvMove-Itemのエイリアス)は、以下のようにファイルを移動・または名前を変更するコマンドレットである。

1
mv [移動元のファイル名] [移動先のファイル名]

なお、移動先に同じ名前のファイルがある場合、mvはエラーを返す。ここでは、

1
mv $_.Name $NewName

となっているので、現在のファイル名$_.Nameを新しいファイル名$NewNameに変更する。

まとめ

ファイル名に連番を振ってリネームするコマンドレットを再掲する。

1
2
ls | sort Name | 
% {$i = 1} { $NewName = "{0:000}.txt" -f $i; mv $_.Name $NewName; $i++ }

ここから$NewNameを省略し、ファイル名の定義時に$iをインクリメントすると、以下のように短縮できる。

1
ls | sort Name | % {$i = 1} {mv $_.Name ("{0:000}.txt" -f $i++)}

ちなみに、インクリメント演算子++を変数の後ろに置くと、変数の評価後にインクリメントされる。
逆に++を変数の前に置く(++$i)と、インクリメント後に変数の値が評価されるので注意。

追記: ファイルの拡張子を自動で引き継ぐ場合は、以下のコマンドレットを実行する。

1
ls | sort Name | % {$i = 1} {mv $_.Name (("{0:000}" -f $i++) + $_.Extension)}

参考

【Windows】ファイル名を一括で変更する[連番ファイル名] | BIZLOG.TECH

シェアする

Helve
WRITTEN BY
Helve
関西在住、電機メーカ勤務のエンジニア。Twitterで新着記事を配信中です