ファイル名がただの連番になってしまった時に、まとめて名称を変えたいと思う機会がありました。
PowerShell で気軽にさくっと書けますよアピールということで。
目次
どんな状態なのか
元のファイル名
このような適当な名前とします。
Get-ChildItem -Path D:\hoge
Directory: D:\hoge Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2013/09/18 4:50 6087020 01-test 01.txt -a--- 2013/09/18 4:50 18947756 02-test 02.txt -a--- 2013/09/18 4:51 14925836 03-test 03.txt -a--- 2013/09/18 4:51 20730572 04-test 04.txt -a--- 2013/09/18 4:51 15803132 05-test 05.txt -a--- 2013/09/18 4:52 23336588 06-test 06.txt -a--- 2013/09/18 4:52 18079868 07-test 07.txt -a--- 2013/09/18 4:52 17882300 08-test 08.txt -a--- 2013/09/18 4:53 21953612 09-test 09.txt -a--- 2013/09/18 4:53 24620780 10-test 10.txt -a--- 2013/09/18 4:53 18493820 11-test 11.txt -a--- 2013/09/18 4:54 21231548 12-test 12.txt -a--- 2013/09/18 4:54 25775612 13-test 13.txt -a--- 2013/09/18 4:54 16760396 14-test 14.txt -a--- 2013/09/18 4:54 23233100 15-test 15.txt -a--- 2013/09/18 4:55 17924636 16-test 16.txt -a--- 2013/09/18 4:55 20438924 17-test 17.txt -a--- 2013/09/18 4:55 20890508 18-test 18.txt -a--- 2013/09/18 4:55 21925388 19-test 19.txt -a--- 2013/09/18 4:56 20972828 20-test 20.txt -a--- 2013/09/18 4:56 22779164 21-test 21.txt -a--- 2013/09/18 4:56 27219740 22-test 22.txt -a--- 2013/09/18 4:57 22856780 23-test 23.txt -a--- 2013/09/18 4:57 22247612 24-test 24.txt -a--- 2013/09/18 4:57 23854028 25-test 25.txt -a--- 2013/09/18 4:57 18881900 26-test 26.txt -a--- 2013/09/18 4:57 16640444 27-test 27.txt
変更後の名前
一覧を適当にファイルに持っていたとしましょう。 ファイルには空白行があり、そこは省きたいモノとします。
Get-Content D:\newnames.txt
01-swordland to be continued 02-friendly feelings 03-sorrowfully 04-critical phase 05-victory 06-a new world of fairies 07-fly higher and faster 08-in time of peace 09-fly, if you can 10-fight with a devil 11-she is still sleeping 12-past sadness 13-is this love 14-town in the morning 15-climbing up the world tree 16-I wonder 17-Yui 18-is this love piano only ver. 19-Oberon 20-in the cage 21-got to win 22-aerial fight 23-false king 24-last flight 25-reconciliation 26-dance with me 27-aincrad
マッチング
- 元のファイル名の番号と、newnames.txt の番号で一致させてファイル名を変更します
- 拡張子は残します
- ファイル名からスペースは外しましょう
変更スクリプト
PowerShell で さっくり書けて楽です。
$names = Select-String -Path D:\newnames.txt -Pattern "\W" | select -ExpandProperty Line $targetpath = 'D:\hoge' Get-ChildItem -Path $targetpath ` | %{ # get original extention $extention = $_.Extension # get matching names [string]$matchingname = $names -like "*$($_.Name.Substring(0,2))*" # configure new name $newname = [System.IO.Path]::ChangeExtension($matchingname.Replace(" ",""),$extention) # rename items if ($matchingname) { Rename-Item -Path $_.FullName -NewName $newname } }
-Whatif で Rename-Item を実行してみると
What if: Performing the operation "Rename File" on target "Item: D:\hoge\01-test 01.txt Destination: D:\hoge\01-swordlandtobecontinued.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\02-test 02.txt Destination: D:\hoge\02-friendlyfeelings.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\03-test 03.txt Destination: D:\hoge\03-sorrowfully.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\04-test 04.txt Destination: D:\hoge\04-criticalphase.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\05-test 05.txt Destination: D:\hoge\05-victory.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\06-test 06.txt Destination: D:\hoge\06-anewworldoffairies.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\07-test 07.txt Destination: D:\hoge\07-flyhigherandfaster.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\08-test 08.txt Destination: D:\hoge\08-intimeofpeace.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\09-test 09.txt Destination: D:\hoge\09-fly,ifyoucan.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\10-test 10.txt Destination: D:\hoge\10-fightwithadevil.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\11-test 11.txt Destination: D:\hoge\11-sheisstillsleeping.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\12-test 12.txt Destination: D:\hoge\12-pastsadness.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\13-test 13.txt Destination: D:\hoge\13-isthislove.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\14-test 14.txt Destination: D:\hoge\14-towninthemorning.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\15-test 15.txt Destination: D:\hoge\15-climbinguptheworldtree.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\16-test 16.txt Destination: D:\hoge\16-Iwonder.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\17-test 17.txt Destination: D:\hoge\17-Yui.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\18-test 18.txt Destination: D:\hoge\18-isthislovepianoonlyver.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\19-test 19.txt Destination: D:\hoge\19-Oberon.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\20-test 20.txt Destination: D:\hoge\20-inthecage.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\21-test 21.txt Destination: D:\hoge\21-gottowin.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\22-test 22.txt Destination: D:\hoge\22-aerialfight.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\23-test 23.txt Destination: D:\hoge\23-falseking.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\24-test 24.txt Destination: D:\hoge\24-lastflight.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\25-test 25.txt Destination: D:\hoge\25-reconciliation.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\26-test 26.txt Destination: D:\hoge\26-dancewithme.txt". What if: Performing the operation "Rename File" on target "Item: D:\hoge\27-test 27.txt Destination: D:\hoge\27-aincrad.txt".
では、実行してみて、結果を見てみましょう。
Get-ChildItem -Path D:\hoge
Directory: D:\hoge Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2013/09/18 4:50 6087020 01-swordlandtobecontinued.txt -a--- 2013/09/18 4:50 18947756 02-friendlyfeelings.txt -a--- 2013/09/18 4:51 14925836 03-sorrowfully.txt -a--- 2013/09/18 4:51 20730572 04-criticalphase.txt -a--- 2013/09/18 4:51 15803132 05-victory.txt -a--- 2013/09/18 4:52 23336588 06-anewworldoffairies.txt -a--- 2013/09/18 4:52 18079868 07-flyhigherandfaster.txt -a--- 2013/09/18 4:52 17882300 08-intimeofpeace.txt -a--- 2013/09/18 4:53 21953612 09-fly,ifyoucan.txt -a--- 2013/09/18 4:53 24620780 10-fightwithadevil.txt -a--- 2013/09/18 4:53 18493820 11-sheisstillsleeping.txt -a--- 2013/09/18 4:54 21231548 12-pastsadness.txt -a--- 2013/09/18 4:54 25775612 13-isthislove.txt -a--- 2013/09/18 4:54 16760396 14-towninthemorning.txt -a--- 2013/09/18 4:54 23233100 15-climbinguptheworldtree.txt -a--- 2013/09/18 4:55 17924636 16-Iwonder.txt -a--- 2013/09/18 4:55 20438924 17-Yui.txt -a--- 2013/09/18 4:55 20890508 18-isthislovepianoonlyver.txt -a--- 2013/09/18 4:55 21925388 19-Oberon.txt -a--- 2013/09/18 4:56 20972828 20-inthecage.txt -a--- 2013/09/18 4:56 22779164 21-gottowin.txt -a--- 2013/09/18 4:56 27219740 22-aerialfight.txt -a--- 2013/09/18 4:57 22856780 23-falseking.txt -a--- 2013/09/18 4:57 22247612 24-lastflight.txt -a--- 2013/09/18 4:57 23854028 25-reconciliation.txt -a--- 2013/09/18 4:57 18881900 26-dancewithme.txt -a--- 2013/09/18 4:57 16640444 27-aincrad.txt
説明
不要な方も多いと思いますが、せっかくなので簡単に説明します。
新しいファイル名の一覧をテキストから取得
$names = Select-String -Path D:\newnames.txt -Pattern "\W" | select -ExpandProperty Line
ファイルを読むだけなら、 Get-Content
Cmdlet (要は cat) もありますが、今回は空白行を省くようにする必要があります。
このようなときは、正規表現で検査しつつ読み取れる Select-String
Cmdlet が便利です。
ご存知の\W
を使えばいいですね。
パイプ|
の先で select -ExpandProperty Line
としたのは、Lineプロパティのみを取得するためです。
同様の書き方として、プロパティを指定してもいいでしょう。
$names = (Select-String -Path D:\newnames.txt -Pattern "\W").Line
対象となるファイル一覧を取得
ご存知の ls
や dir
に相当する Get-ChildItem
Cmdletを利用して、対象パス D:\hoge
からファイル一覧を取得しています。
$targetpath = 'D:\hoge' Get-ChildItem -Path $targetpath
ここで Where-Object"
にパイプラインで渡せば、対象となるファイルを拡張子など任意のプロパティでフィルタ可能です。
たとえば、拡張子が .txtのファイルだけを対象にするならこうです。
$targetpath = 'D:\hoge' Get-ChildItem -Path $targetpath | where Extension -eq ".txt"
取得した各ファイルごとに処理を行う
| %{ # get original extention $extention = [System.IO.Path]::GetExtension($_.FullName) # get matching names [string]$matchingname = $names -like "*$($_.Name.Substring(0,2))*" # configure new name $newname = [System.IO.Path]::ChangeExtension($matchingname.Replace(" ",""),$extention) # rename items if ($matchingname) { Rename-Item -Path $_.FullName -NewName $newname } }
ここでは、 Get-ChildItem
の結果をパイプ|
で受けて、 Foreach-Object (Alias は %)
で処理しています。Foreach-Object
と書くのは面倒です (
# 略さないとこう Foreach-Object { } # Aliasで略す foreach { } # もう一つのAliasで %{ }
なお、 Foreach-Object
内部では、パイプラインを通して渡されたファイルオブジェクトが自動変数 $_
に格納されます。
# Get-ChildItemで取得したオブジェクトが $_ に格納されている。 Get-ChildItem -Path -D:\hoge | %{ $_ }
さらに PowerShell V4.0 からは、 -PipelineObject
で、オブジェクトを操作してからパイプラインに渡せます。
続いて、現在の Extensionを取得します。 自動変数から Extension プロパティを取得します。
$extention = $_.Extension
.NET でもいいです。
# get original extention $extention = [System.IO.Path]::GetExtension($_.FullName)
Get-Item
や Get-ItemProperty
Cmdletでもいいでしょう。
# get original extention $extention = (Get-ItemProperty -Path $_.FullName).Extension
次に、対象のファイル名と、テキストから取得したファイル名でマッチングします。 今回は、頭2文字の数字で。
# get matching names [string]$matchingname = $names -like "*$($_.Name.Substring(0,2))*"
新しい名前を定めます。 取得したもともとの拡張子を忘れないように。
# configure new name $newname = [System.IO.Path]::ChangeExtension($matchingname.Replace(" ",""),$extention)
マッチングが該当した場合だけ実行します。
# rename items if ($matchingname) { Rename-Item -Path $_.FullName -NewName $newname }
以上です。 Aliasを使って、パラメータ省略もして、パイプラインで繋げば どんどん短くなりますが、そこは周りが読めるかどうか、書きやすさ などを考慮しましょう。
終わり
ファイル名変更ソフトもいいのでしょうが、PowerShell も自由に操れるのでお勧めです。 身近なところから、PowerShell を試してみませんか?
追記
敬愛する 帝国兵さま と はぐれメタルさま からしっかりやれって言われたので修正します。
こんな適当記事が見つかるとは。。。。。。。。。。。。ぐぬぬにゃお
ファイル名のバリデーション と ちょこちょこっと直しました。
# Get invalid charactors for filename $invalidfilename = [System.IO.Path]::GetInvalidFileNameChars() # Get names from namelist $namelist = "D:\newnames.txt" $names = Select-String -Path $namelist -Pattern "\W" | select -ExpandProperty Line # get filenames from targetpath $targetpath = 'D:\hoge' Get-ChildItem -Path $targetpath ` | %{ # get original extention $extention = $_.Extension # get matching names [string]$matchingname = $names -like "*$($_.Name.Substring(0,2))*" if ($matchingname) { # get index of validation (valid = -1) $validationIndex = $matchingname.IndexOfAny($invalidfilename) # execute rename if ($validationIndex -eq "-1") { # configure new name $newname = [System.IO.Path]::ChangeExtension($matchingname.Replace(" ",""),$extention) # rename item Write-Warning -Message ("running rename with {0} to {1}" -f $_.FullName, $newname) Rename-Item -Path $_.FullName -NewName $newname } else { Write-Error -Message ("{0} contains invalid charactor. index : {1}" -f $matchingname, $validationIndex) } } }
元の newnames.txt に ファイル名に使えない文字が含まれている場合、エラーを明示します。 newnames.txt がこうだとします。
01-swordland to be continuedfghfghfh>>> 02-friendly feelings 03-sorrowfully 04-critical phase 05-victory 06-a new world of fairies 07-fly higher and faster 08-in time of peace 09-fly, if you can 10-fight with a devil 11-she is still sleeping 12-past sadness 13-is this love 14-town in the morning 15-climbing up the world tree 16-I wonder 17-Yui 18-is this love piano only ver. 19-Oberon 20-in the cage 21-got to win 22-aerial fight 23-false king 24-last flight 25-reconciliation 26-dance with me 27-aincrad
結果、01-swordland to be continuedfghfghfh>>>
の>
は使えないので、エラー検出します。
D:\GitHub\PowerShellUtil\Rename-FileNames\Rename-FileNames.ps1 : 01-swordland to be continuedfghfghfh>>> contains invalid charactor. index : 36 + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Rename-FileNames.ps1 WARNING: running rename with D:\hoge\02-friendlyfeelings.txt to 02-friendlyfeelings.txt WARNING: running rename with D:\hoge\03-sorrowfully.txt to 03-sorrowfully.txt WARNING: running rename with D:\hoge\04-criticalphase.txt to 04-criticalphase.txt WARNING: running rename with D:\hoge\05-victory.txt to 05-victory.txt WARNING: running rename with D:\hoge\06-anewworldoffairies.txt to 06-anewworldoffairies.txt WARNING: running rename with D:\hoge\07-flyhigherandfaster.txt to 07-flyhigherandfaster.txt WARNING: running rename with D:\hoge\08-intimeofpeace.txt to 08-intimeofpeace.txt WARNING: running rename with D:\hoge\09-fly,ifyoucan.txt to 09-fly,ifyoucan.txt WARNING: running rename with D:\hoge\10-fightwithadevil.txt to 10-fightwithadevil.txt WARNING: running rename with D:\hoge\11-sheisstillsleeping.txt to 11-sheisstillsleeping.txt WARNING: running rename with D:\hoge\12-pastsadness.txt to 12-pastsadness.txt WARNING: running rename with D:\hoge\13-isthislove.txt to 13-isthislove.txt WARNING: running rename with D:\hoge\14-towninthemorning.txt to 14-towninthemorning.txt WARNING: running rename with D:\hoge\15-climbinguptheworldtree.txt to 15-climbinguptheworldtree.txt WARNING: running rename with D:\hoge\16-Iwonder.txt to 16-Iwonder.txt WARNING: running rename with D:\hoge\17-Yui.txt to 17-Yui.txt WARNING: running rename with D:\hoge\18-isthislovepianoonlyver.txt to 18-isthislovepianoonlyver.txt WARNING: running rename with D:\hoge\19-Oberon.txt to 19-Oberon.txt WARNING: running rename with D:\hoge\20-inthecage.txt to 20-inthecage.txt WARNING: running rename with D:\hoge\21-gottowin.txt to 21-gottowin.txt WARNING: running rename with D:\hoge\22-aerialfight.txt to 22-aerialfight.txt WARNING: running rename with D:\hoge\23-falseking.txt to 23-falseking.txt WARNING: running rename with D:\hoge\24-lastflight.txt to 24-lastflight.txt WARNING: running rename with D:\hoge\25-reconciliation.txt to 25-reconciliation.txt WARNING: running rename with D:\hoge\26-dancewithme.txt to 26-dancewithme.txt WARNING: running rename with D:\hoge\27-aincrad.txt to 27-aincrad.txt
なんだか、すいませんでした。