読者です 読者をやめる 読者になる 読者になる

素敵なおひげですね

PowerShellを中心に気分で書いているブログです。

大量のファイルをPowerShellのコマンドで一括リネームする

クラスメソッドさんのこのエントリが人気を博してるので人気にあやかるためにPowerShellで同じことをしてみました。

dev.classmethod.jp

前提

動作はPowerShell 4.0な環境で確かめてますが他のバージョンでも動くはずです。
今回は適当なディレクトC:\Tempでコマンドを実行しています。

# 前準備
mkdir C:\Temp
cd C:\Temp

また、プロンプトからの実行を意識してエイリアスもガンガン使っていきます。

Case 1. 元のファイル名に文字を加える

001.txt~999.txt001_document.md~999_document.mdに変えます。
本エントリではファイルの生成もコマンドでやってみます。

ファイルの生成

PS C:\Temp> 1..999 | % { $_ | Out-File ("{0:000}.txt" -f $_) }

リネーム

PS C:\Temp> ls | % { $NewName = "{0}_document.md" -f $_.BaseName; mv $_.Name $NewName }

解説

基本的にPowerShellではForEach-Objcet(%)スクリプトブロックを渡せるのでブロック内で新しいファイル名を組み立ててMove-Item(mv)コマンドでファイルを移動すれば良いだけになります。

今回のパターンではパイプラインで渡されるのがファイルオブジェクト(System.IO.FileInfo)であることが確定しているので、拡張子を除いたBaseNameプロパティを使えば名前の変更はあっという間にできます。

Case 2. 元のファイル名に昇順で数字を追加する

a.txt~z.txt01_a.txt~26_z.txtに変えます。

ファイルの生成

PS C:\Temp> 1..26 | % { $_ | Out-File ("{0}.txt" -f [char]($_+96)) }

リネーム

PS C:\Temp> ls | sort Name | % {$i = 1} { $NewName = "{0:00}_{1}" -f $i, $_.Name ; mv $_.Name $NewName; $i++ }

解説

名前に連番を入れるのにはちょっとだけ工夫が必要になります。
ForEach-Objcet(%)内では連番を表す自動変数は存在しないので、カウンターとなる変数$iを使って連番を生成しています。

スクリプトブロックを2つ使っていますが、最初の{$i = 1}はBeginブロックでパイプラインの各オブジェクトを処理する前に一度だけ実行されます。
次のスクリプトブロックがProcessブロックとなりパイプラインのオブジェクト毎に実行される部分になります。

これは以下のコマンドと同義になります。

PS C:\Temp> ls | sort Name | ForEach-Object -Begin { $i = 1 } -Process { $NewName = "{0:00}_{1}" -f $i, $_.Name ; mv $_.Name $NewName; $i++ }

また、今回は使いませんでしたがパイプラインの終了時に呼ばれるEndブロックも指定することができます。

ForEach-Objcet(%)の詳細についてはMSDNで確認してください。

Case 3. 元のファイル名に日付を加える

a.txt~z.txt[作成日付]_a.txt~[作成日付]_z.txtに変えます。

ファイルの生成

PS C:\Temp> 1..26 | % { $_ | Out-File ("{0}.txt" -f [char]($_+96)) }
# 作成時刻を過去100日間のランダムな日付に変更する
PS C:\Temp> ls | % { $_.CreationTime = (Get-Date).AddDays((Get-Random -Minimum -100 -Maximum 0)) }

リネーム

PS C:\Temp> ls | % { $NewName = "{0:MMdd}_{1}" -f $_.CreationTime, $_.Name ; mv $_.Name $NewName }

解説

ファイルの作成時刻はCreationTimeプロパティから取得できますので{0:MMdd}形式で月日を取得してリネームするファイル名を生成しています。

まとめ

すべてをオブジェクトで扱いパイプラインにブロックを渡せるPowerShellではファイルの属性を利用したリネーム処理などは最も得意とする分野だと思います。

ちょっと取っつきにくいところもあるPowerShellですが、状況によっては非常に便利に利用できるので使えるところでは積極的に使うと良いと思います。