英文:
PowerShell - Work with counter and renaming of files
问题
以下是已经翻译好的代码部分:
$count=1000
Get-ChildItem -Recurse -Include *.jpg | ForEach-Object -Process { Rename-Item -LiteralPath $_ -NewName ("PHOTO{0}_{1}_{2}" -f $script:count, $_.Directory.Name, $_.BaseName) -WhatIf }
如果你需要任何进一步的帮助,请随时告诉我。
英文:
Please help with the following situation:
There are many photos need to be renamed according to the name of directory folder, where they are located + add index at the end of each new name in format PHOTO1000_NAMEA_1, PHOTO1001_NAMEA_2, PHOTO1002_NAMEB_1, PHOTO1003_NAMEB_2, PHOTO1004_NAMEC_1, PHOTO1005_NAMEC_2, etc.
Where:
a) PHOTO1000 (1001,1002) = counter of total quantity of renamed photos;
b) _1 (_2,_3) = indexing number of concrete new name of item.
In my version of code in part a) counter did not calculate items from "1000", i++.
$count=1000
Get-ChildItem -Recurse -Include *.jpg | ForEach-Object -Process { Rename-Item -LiteralPath $_ -NewName ("PHOTO_{0}_{1}{2}" -f $script:count, $_.Directory.Name,$_.Extension) -WhatIf }
Please help with correct format of code.
Thanks!!
答案1
得分: 2
<!-- language-all: sh -->
使用两个[哈希表](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Hash_Tables),结合[延迟绑定脚本块](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_script_blocks#using-delay-bind-script-blocks-with-parameters),可以实现您的任务:
$totalCount = @{ value = 0 } # 总重命名文件的计数
$countPerDir = @{ } # 每个目录名称的重命名文件计数
Get-ChildItem -Recurse -Include *.jpg |
Rename-Item -NewName {
'PHOTO_{0}{1}{2}{3}' -f ++$totalCount.value,
$.Directory.Name,
++$countPerDir[$.Directory.Name],
$.Extension
} -WhatIf
<sup>注意:上面命令中的 [`-WhatIf` 通用参数](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_commonparameters#-whatif) 用于 _预览_ 操作。一旦确定操作会按您的期望执行,请删除 `-WhatIf` 并重新执行。</sup>
注意:
* 通过使用 [`Rename-Item`](https://learn.microsoft.com/powershell/module/microsoft.powershell.management/rename-item),您实际上是在原地重命名文件,而不是在单一的目标目录中;如果需要后者,请改用 [`Move-Item`](https://learn.microsoft.com/powershell/module/microsoft.powershell.management/move-item),并使用其 `-Destination` 参数。
* `$totalCount` 之所以是哈希表而不是简单的 `[int]` 变量,是因为延迟绑定脚本块在调用者的 _子_ 作用域中运行(与 `ForEach-Object` 和 `Where-Object` 脚本块不同),从子作用域引用哈希表使得能够跨作用域边界更新其条目。
* `$countPerDir` 哈希表跟踪每个目录名称中已重命名的文件数。`++$countPerDir[$_.Directory.Name]` 利用了两个行为:
* 对尚不存在的条目进行赋值会隐式 *创建* 该条目(使用给定的键)。
* 对刚刚创建的新条目应用 `++` 实际上将其视为 `0` 并返回 `1`。
英文:
<!-- language-all: sh -->
You can use two hashtables in combination with a delay-bind script block to implement your task:
$totalCount = @{ value = 0 } # count of renamed files overall
$countPerDir = @{ } # count of renamed files per directory name
Get-ChildItem -Recurse -Include *.jpg |
Rename-Item -NewName {
'PHOTO_{0}_{1}_{2}_{3}' -f ++$totalCount.value,
$_.Directory.Name,
++$countPerDir[$_.Directory.Name],
$_.Extension
} -WhatIf
<sup>Note: The -WhatIf
common parameter in the command above previews the operation. Remove -WhatIf
and re-execute once you're sure the operation will do what you want.</sup>
Note:
-
By using
Rename-Item
, you're actually renaming the files in place, not in a single, flat target directory; if you want the latter, useMove-Item
with its-Destination
parameter instead. -
The only reason
$totalCount
is a hashtable rather than a simple[int]
variable is that delay-bind script blocks run in a child scope of the caller (unlikeForEach-Object
andWhere-Object
script blocks), and referencing a hashtable from the child scope enables updating its entries across scope boundaries. -
The
$countPerDir
hashtable keeps track of how any files per directory name have been renamed.++$countPerDir[$_.Directory.Name]
takes advantage of two behaviors:- Assigning to an entry that didn't previously exists implicitly creates such an entry (with the given key).
- Applying
++
to new entry that was just created effectively treats it like0
and returns1
.
答案2
得分: 0
我根据您的问题理解提供了一个解决方案。
确保使用投票机制标记正确答案,如果对提供的内容满意。
# 设置包含要重命名的照片的目录路径
$dirPath = "C:\Temp\Photo"
$counter = 1000
# 获取指定路径中的所有目录
$dirs = Get-ChildItem -Path $dirPath -Directory -Recurse
# 循环遍历每个目录
foreach ($dir in $dirs) {
# 获取当前目录中的所有文件
$files = Get-ChildItem -Path $dir.FullName -File -Filter '*.jpg'
# 初始化当前文件索引的计数器
$index = 1
# 遍历当前目录中的每个文件
foreach ($file in $files) {
# 构建新文件名
# ("PHOTO_{0}_{1}{2}" -f $script:count, $_.Directory.Name, $_.Extension)
if ($file.BaseName.StartsWith('PHOTO')) {
Write-Warning ('文件 {0} 已经被重命名' -f $file.FullName)
Continue
}
$newName = 'PHOTO{0}_{1}_{2}{3}' -f $counter, $file.BaseName, $index, $file.Extension
# 重命名文件
Rename-Item -Path $file.FullName -NewName $newName
# 增加文件索引
$index++
$counter++
}
}
英文:
I have provided a solution as I understood your question.
Make sure to use the voting mechanism to mark the correct answer if satisfied with what was provided.
# Set the path to the directory containing the photos to rename
$dirPath = "C:\Temp\Photo"
$counter = 1000
# Get all directories in the specified path
$dirs = Get-ChildItem -Path $dirPath -Directory -Recurse
# Loop through each directory
foreach ($dir in $dirs) {
# Get all files in the current directory
$files = Get-ChildItem -Path $dir.FullName -File -Filter '*.jpg'
# Initialize a counter for the current file index
$index = 1
# Loop through each file in the current directory
foreach ($file in $files) {
# Build the new file name
# ("PHOTO_{0}_{1}{2}" -f $script:count, $_.Directory.Name,$_.Extension)
if ($file.BaseName.StartsWith('PHOTO')) {
Write-Warning ('File {0} has alread been renamed' -f $file.FullName)
Continue
}
$newName ='PHOTO{0}_{1}_{2}{3}' -f $counter,$file.BaseName,$index, $file.Extension
# Rename the file
Rename-Item -Path $file.FullName -NewName $newName
# Increment the file index
$index++
$counter++
}
}
答案3
得分: 0
我不看到你调用 $counter。你初始化它,但在 foreach 中没有再次调用它。
你有两个计数器 - 所有照片的总数,然后是基于 NAME_ 的索引,看起来是目录名称。
第一个计数器很简单 - 每次迭代后只需添加 $counter++。$index 只需基于目录 - 最简单的方法可能是根据目录分组,然后 $index++
看,我的答案
$jpgs = Get-ChildItem -Recurse -Include *.jpg | group -Property Directory
$counter = 1000
foreach ($group in $jpgs) {
$index = 1
foreach ($item in $group.Group) {
rename-item -LiteralPath $item -NewName ("PHOTO{0}_{1}_{2}{3}" -f $counter, $item.Directory.Name, $index, $item.Extension)
$counter++
$index++
}
}
看,我的结果
执行操作“Rename File”目标“项目:C:\Users\Doco\Downloads220721_140129.jpg 目标:C:\Users\Doco\Downloads\PHOTO1000_Downloads_1.jpg”。
执行操作“Rename File”目标“项目:C:\Users\Doco\Downloads\IMG_20220720_211337_720.jpg 目标:C:\Users\Doco\Downloads\PHOTO1001_Downloads_2.jpg”。
执行操作“Rename File”目标“项目:C:\Users\Doco\Downloads\IMG_20220720_211337_773.jpg 目标:C:\Users\Doco\Downloads\PHOTO1002_Downloads_3.jpg”。
执行操作“Rename File”目标“项目:C:\Users\Doco\Downloads\IMG_20220721_203852_286.jpg 目标:C:\Users\Doco\Downloads\PHOTO1003_Downloads_4.jpg”。
执行操作“Rename File”目标“项目:C:\Users\Doco\OneDrive\Desktop\birthday invite.jpg 目标:C:\Users\Doco\OneDrive\Desktop\PHOTO1004_Desktop_1.jpg”。
执行操作“Rename File”目标“项目:C:\Users\Doco\OneDrive\Desktop\boop.jpg 目标:C:\Users\Doco\OneDrive\Desktop\PHOTO1005_Desktop_2.jpg”。
现在只需删除 -whatif。显然。
英文:
i don't see you calling $counter. You initiate it, but don't call it again in the foreach.
You have 2 counters going - total of all photos, and then index which is based off of NAME_ which looks like the directory name.
First counter is easy - just add $counter++ after each iteration. $index just needs to be based off of directory - probably simplest way to do this is group everything off of directory, and then $index++
behold - my answer
$jpgs = Get-ChildItem -Recurse -Include *.jpg | group -Property Directory
$counter = 1000
foreach ($group in $jpgs) {
$index = 1
foreach ($item in $group.Group) {
rename-item -LiteralPath $item -NewName ("PHOTO{0}_{1}_{2}{3}" -f
$counter, $item.Directory.Name,$index ,$item.Extension) -
WhatIf;$counter++;$index++}}
behold - my results
Performing the operation "Rename File" on target "Item: C:\Users\Doco\Downloads220721_140129.jpg Destination: C:\Users\Doco\Downloads\PHOTO1000_Downloads_1.jpg".
What if: Performing the operation "Rename File" on target "Item: C:\Users\Doco\Downloads\IMG_20220720_211337_720.jpg Destination: C:\Users\Doco\Downloads\PHOTO1001_Downloads_2.jpg".
What if: Performing the operation "Rename File" on target "Item: C:\Users\Doco\Downloads\IMG_20220720_211337_773.jpg Destination: C:\Users\Doco\Downloads\PHOTO1002_Downloads_3.jpg".
What if: Performing the operation "Rename File" on target "Item: C:\Users\Doco\Downloads\IMG_20220721_203852_286.jpg Destination: C:\Users\Doco\Downloads\PHOTO1003_Downloads_4.jpg".
What if: Performing the operation "Rename File" on target "Item: C:\Users\Doco\OneDrive\Desktop\birthday invite.jpg Destination: C:\Users\Doco\OneDrive\Desktop\PHOTO1004_Desktop_1.jpg".
What if: Performing the operation "Rename File" on target "Item: C:\Users\Doco\OneDrive\Desktop\boop.jpg Destination: C:\Users\Doco\OneDrive\Desktop\PHOTO1005_Desktop_2.jpg".
Now just remove -whatif. Obviously
答案4
得分: 0
这是我的版本,使用引用变量来计数:
[ref]$Total = 0
(Get-ChildItem -Directory -Recurse) | ForEach {
$_ | Get-ChildItem *.jpg -File | ForEach -Begin {[ref]$subTotal = 0} -Process {
$_ | Rename-Item -NewName {
'Photo_{0:d4}_{1}_{2}{3}' -f $Total.Value++ , $_.Directory.Name , $subTotal.Value++ , $_.Extension
} -WhatIf
}
}
请注意,代码部分不被翻译。
英文:
Here's my version, using reference variables for the counters:
[ref]$Total = 0
(Get-ChildItem -Directory -Recurse) | ForEach {
$_ | Get-ChildItem *.jpg -File | ForEach -Begin {[ref]$subTotal = 0} -Process {
$_ | Rename-Item -NewName {
'Photo_{0:d4}_{1}_{2}{3}' -f $Total.Value++ , $_.Directory.Name , $subTotal.Value++ , $_.Extension
} -WhatIf
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论