I want to write this down mainly to help myself remember, but maybe others will find this useful. I will probably try to spend some more time documenting various little useful Powershell snippets I have been working on and using. Mass renaming of files is something I always find myself needing to do and looking up how to do it every time. I am usually on Windows, so I will show how to with Powershell. I mostly use it when downloading a series of files that are not named the way I want or need. So let's use an example of a TV show. This TV show has multiple Seasons. I try to organize it by TvShowName\SeasonXX\TVShowName SXXEYY.mkv, or something like that. Assuming they are already in order, as they usually are, this is actually a really simple process. Let's assume we have TvShowName Season 1 I am trying to rename.
# declare an incremental value
$n = 1
# Feed everything into a loop with a "pipe"
$(Get-ChildItem).Name | Foreach-Object {
# The $_ is the current item in the loop, -f is string format, stuff in $() treats the output as a variable
Rename-Item $_ $("TvShowName S01E{0:00}.mkv" -f $n)
# Increment $n by 1
$n++
}
This would leave us with a folder resulting in:
TvShowName S01E01.mkv
TvShowNameS01E02.mkv
...
Easy, right? However, that would be a pain to type all that out every time, so let's short hand this for on-the-fly name changes in a live shell.
$n=1;$(gci).name|%{rni $_ $("TvShowName S01E{0:00}.mkv" -f $n++}
This is a bit harder to read, but it has the same results. The $n++ being on the same line as the format is possible thanks to order of operations. The incrementing of $n does not occur until after the format. I also use common aliases that Powershell has in place by default.
Now let's expand upon this just a little bit more, let's say I want to include the original extension because it might not all be the same. I will modify the expanded version to show this.
$n = 1
Get-ChildItem | Foreach-Object {
Rename-Item $_.Name $("TvShowName S01E{0:00}{1}" -f $n, $_.Extension)
$n++
}
Now it is becoming a little more robust. Luckily for us, the extension includes the period, so one less character. Now let's further re-organize this code to be just a bit more readable since we understand it a little bit better now.
Get-ChildItem | Foreach-Object {$n = 1} {
Rename-Item $_.Name $("TvShowName S01E{0:00}{1}" -f $n++, $_.Extension)
}
So the change here is super simple. The Foreach-Object block can take multiple script blocks. If it only gets one, that's the process block. If it gets 2, the first is a block it run BEFORE running the process block. If it gets 3 or more, the last becomes what it runs when it is done and the middle all become process blocks. So basically, moving the $n = 1 to be in a more traditional initialization position for a loop. The problem with this is we are looping with a lot of assumptions. We assume there will be an order to this and what we want to name will be easy to do. Generally, on the fly typing commands, this is what you would be doing. Anything more robust and you will likely want to type out a full fledge function, perhaps even create a module to do so. As you saw at the beginning, this relatively simple task can be an easy one-liner with very little typing thanks to aliases, with the final condensed version being like so.
gci|%{$n=1}{rni $_.name $("TvShowName S01E{0:00}{1}" -f $n++,$_.extension)}
To be honest, I love typing out those types of one-liners, feels like being a movie hacker and a typical passer-by is not going to easily recognize what you are doing. Granted, in a movie they would probably show you some big long graphical "hello, world!" code and tell you it's a super awesome malware that can compromise the entire nuclear system of some country. For now, I will just keep it simple with this. Experiment, tweak, and expand this to your liking.
No comments:
Post a Comment