I like using all Powershell commands when I can. After a bit of testing, this is the best I can do.
$source = "C:\test"
$destination = "C:\test2"
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"
$bin = Get-ChildItem -Path $source | Where-Object {$_.Name -match $filter}
foreach ($item in $bin) {Copy-Item -Path $item.FullName -Destination $destination}
The first three lines are just to make this easier to read, you can define the variables inside the actual commands if you want. The key to this code sample is the the "Where-Object" command which is a filter that accepts regular expression matching. It should be noted that regular expression support is a little weird. I found a PDF reference card here that has the supported characters on the left side.
[EDIT]
As "@Johannes Rössel" mentioned, you can also reduce the last two lines down to a single line.
((Get-ChildItem -Path $source) -match $filter) | Copy-Item -Destination $destination
The main difference is that Johannes's way does object filtering and my way does text filtering. When working with Powershell, it's almost always better to use objects.
[EDIT2]
As @smoknheap mentioned, the above scripts will flatten out the folder structure and put all your files in one folder. I'm not sure if there is a switch that retains folder structure. I tried the -Recurse switch and it doesn't help. The only way I got this to work is to go back to string manipulation and add in folders to my filter.
$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
}
I'm sure that there is a more elegant way to do this, but from my tests it works. It gather s everything and then filters for both name matches and folder objects. I had to use the ToString() method to gain access to the string manipulation.
[EDIT3]
Now if you want to report the pathing to make sure you have everything correct. You can use the "Write-Host" Command. Here's the code that will give you some hints as to what's going on.
cls
$source = "C:\test"
$destination = "C:\test2"
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"
$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
Write-Host "
----
Obj: $item
Path: "$item.fullname"
Destination: "$item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
}
This should return the relevant strings. If you get nothing somewhere, you'll know what item is having problems with.
Hope this helps
Unix has several powerful ways to rename files. Here's one that uses zsh (make sure you have it installed). This first renames the directories, then renames the files in the directories.
autoload zmv
zmv -o -i '(?)(??)(??)(?)(???)(?)' '$1-$2-$3-$4-$5-$6'
zmv -o -i '(*)/(?)(??)(??)(?)(???)(?).(*)' '$1/$2-$3-$4-$5-$6-$7.$8'
It's not clear from your question whether the directories can nest. If they do, here's a single command that takes care of both directories and files, taking advantage of the fact that a single pattern replacement works for both:
zmv -o -i '(**/)(?)(??)(??)(?)(???)(*)' '$1$2-$3-$4-$5-$6-$7$8'
If you pass the -n
option to zmv
, it will show what the command would have done without actually moving the files. I use -o -i
in my example so that it prompts for confirmation if it would overwrite a file and performs silently otherwise.
zmv
is documented in the zshcontrib
man page.
Best Answer
I realize this is not exactly a "GUI", but you didn't say anything why that is a requirement, and there are already-written command-line tools that do this; e.g.
perl-rename
:(
-n
turns on "test" mode. When you're satisfied with the output, run again with-v
or no options instead.)