英文:
Powershell - If Folder Exists, Increment Folder Name
问题
我试图查看文件夹是否存在,如果存在,将一个增量添加到文件夹名称,如下所示。
FolderName
- 如果FolderName存在,将文件夹命名为FolderName_1
- 如果FolderName_1存在,将文件夹命名为FolderName_2
到目前为止,这是我拥有的代码,但它不起作用。
$i = 1
if (Test-Path -Path $FolderName) {
$FolderName = $FolderName + '_' + $i
$i++
}
else {
}
我知道我缺少逻辑,只是不确定如何使其工作。感谢您的帮助!
英文:
I'm trying to see if a folder exists, and if it does, add an increment to the folder name, like this.
FolderName
- If FolderName exists, name the folder FolderName_1
- If FolderName_1 exists, name the folder FolderName_2
This is what I have so far, but it doesn't work.
$i = 1
if (Test-Path -Path $FolderName) {
$FolderName = $FolderName + '_'+ $i
$i++
}
else {
}
I know I am missing logic, just not sure how to make this work. Thanks for your help!
答案1
得分: 1
以下是您要翻译的内容:
为了实现一个*健壮的*解决方案,您必须检查所有当前存在的与名称模式匹配的文件夹,并从中提取嵌入的最高数字,然后将该数字加1:
# 获取名称中任何现有文件夹中嵌入的最高数字。
$highestExistingNum =
Get-ChildItem -ErrorAction Ignore -Directory $FolderName, $FolderName_* |
ForEach-Object { if ($_.Name -match '_(\d+)$') { [int] $Matches.1 } else { 0 } }
Sort-Object -Descending |
Select-Object -First 1
if ($null -ne $highestExistingNum) { # 至少有一个已存在的文件夹?
$FolderName = $FolderName + '_' + (1 + $highestExistingNum)
}
注意:
-
如果您期望有超过10个文件夹,考虑对嵌入的数字进行零填充,以使它们的
Get-ChildItem
输出顺序反映嵌入的数字;例如,对于3位数的0
填充(例如,001
),使用:(1 + $highestExistingNum).ToString('D3')
-
Get-ChildItem
调用查找所有符合原始名称和名称模式(如果有的话)的现有文件夹;-Directory
开关限制处理为文件夹(仅限目录)- 注意:如果未找到任何现有文件夹,则整个管道不输出任何内容。此情况稍后通过将
$highestExistingNum
的值与$null
进行比较来检测。
- 注意:如果未找到任何现有文件夹,则整个管道不输出任何内容。此情况稍后通过将
-
ForEach-Object
调用:-
使用带有正则表达式的
-match
运算符查看给定文件夹名称是否以($
)结尾,后跟一个或多个(+
)数字(\d
),并捕获((...)
)后者。 -
通过自动变量
$Matches
访问捕获的数字字符串并将其转换为整数([int]
)。 -
如果文件夹名称不以数字结尾,则返回
0
。
-
-
Sort-Object
对得到的整数按降序排序(-Descending
),即最高数字首先输出。 -
Select-Object
用于仅选择最高数字-First 1
。- 注意:在PowerShell (Core) 7+中,您可以通过在
Sort-Object
中使用-Top 1
来简化上述过程(即Sort-Object -Descending -Top 1
),从而无需使用Select-Object
调用。
- 注意:在PowerShell (Core) 7+中,您可以通过在
英文:
<!-- language-all: sh -->
For a robust solution you must examine all currently existing folders that match the name pattern and extract the highest embedded number from them, then add 1 to that number:
# Get the highest number embedded in the names of any existing folders.
$highestExistingNum =
Get-ChildItem -ErrorAction Ignore -Directory $FolderName, $FolderName_* |
ForEach-Object { if ($_.Name -match '_(\d+)$') { [int] $Matches.1 } else { 0 } }
Sort-Object -Descending |
Select-Object -First 1
if ($null -ne $highestExistingNum) { # At least 1 preexisting folder?
$FolderName = $FolderName + '_' + (1 + $highestExistingNum)
}
Note:
-
If you expect more than 10 folders, consider zero-padding the embedded numbers, so that their
Get-ChildItem
output order reflects the embedded numbers; e.g., for 3-digit0
padding (e.g.,001
), use:(1 + $highestExistingNum).ToString('D3')
-
The
Get-ChildItem
call finds all existing folders that fit the original name and the name pattern, if any; the-Directory
switch limits processing to folders (directories only)- Note: If no existing folders are found, the whole pipeline outputs nothing. This case is later detected by comparing the value of
$highestExistingNum
to$null
.
- Note: If no existing folders are found, the whole pipeline outputs nothing. This case is later detected by comparing the value of
-
The
ForEach-Object
call:-
uses the
-match
operator with a regex to see if a given folder name ends with ($
) a_
followed by one or more (+
) digits (\d
), and captures ((...)
) the latter. -
accesses the captured string of digits via the automatic
$Matches
variable and converts it to an integer ([int]
). -
if the folder name doesn't end in
_
followed by a number,0
is returned.
-
-
Sort-Object
sorts the resulting integers in descending order (-Descending
), i.e. the highest number is output first. -
Select-Object
is used to select only that highest number-First 1
.- Note: In PowerShell (Core) 7+, you can streamline the above by using
-Top 1
withSort-Object
(i.e.Sort-Object -Descending -Top 1
), which obviates the need for theSelect-Object
call.
- Note: In PowerShell (Core) 7+, you can streamline the above by using
答案2
得分: 0
您缺少使用Rename-Item
以及一些用于检测/更新_i
部分的额外逻辑:
$FolderName = 'foo'
$Target = "C:\"
Get-ChildItem -Path $Target -Directory `
| Where-Object { $_.Name -match "$FolderName`_(\d+)|$FolderName" } `
| ForEach-Object {
if ($_ -match "$FolderName`_(\d+)"){
$NewName = $FolderName + "_$([int]$matches[1] + 1)"
} else {
$NewName = $FolderName + '_1'
}
$OldName = $_.FullName
$NewName = Join-Path $Target $NewName
Write-Host "Found '$($_.FullName)', renaming to '$NewName'"
Rename-Item -Path $OldName -NewName $NewName
}
要详细说明:$FolderName
可能是一个字符串,但我们想要与文件对象交互。我们使用Rename-Item
命令来执行此操作,使用字符串路径。我们还使用简单的正则表达式来处理_i
计数器。
英文:
You are missing the use of Rename-Item
, as well as some extra logic for detecting/updating the _i
part:
$FolderName = 'foo'
$Target = "C:\"
Get-ChildItem -Path $Target -Directory `
| Where-Object { $_.Name -match "$FolderName`_(\d+)|$FolderName"} `
| ForEach-Object {
if ($_ -match "$FolderName`_(\d+)"){
$NewName = $FolderName + "_$([int]$matches[1] + 1)"
} else {
$NewName = $FolderName + '_1'
}
$OldName = $_.FullName
$NewName = Join-Path $Target $NewName
Write-Host "Found '$($_.FullName)', renaming to '$NewName'"
Rename-Item -Path $OldName -NewName $NewName
}
To elaborate: $FolderName
is presumably a string, but we want to interact with a file object. We use the Rename-Item
cmdlet to do so, using the string path. We also use a simple regex to account for the _i
counter.
答案3
得分: 0
你离答案很接近,但你需要使用另一个变量来存储你的目录的“基本名称”,否则你会在原有基础上添加 _1,然后再添加 _2(得到 something_1_2),而不是添加 _2 而不是 _1。
类似这样的代码:
$BaseName = 'MyDir'
$FullName = $BaseName
$i = 0
while (Test-Path $FullName)
{
$FullName = "$BaseName_$i"
$i++
}
英文:
You're quite close, but you need to use another variable to store the 'base name' of your directory: otherwise you're adding _1 and then adding _2 on top of that (getting something_1_2), instead of adding _2 instead of _1.
Something like this:
$BaseName = 'MyDir'
$FullName = $BaseName
$i = 0
while (Test-Path $FullName)
{
$FullName = "$BaseName_$i"
$i++
}
答案4
得分: 0
以下是翻译好的内容:
尝试使用以下while
循环:
$i = 0
$Suffix = ''
while (Test-Path -Path "$FolderName$Suffix" -PathType Container) {
$i++
$suffix = "_$i"
}
$FolderName = "$FolderName$Suffix"
$FolderName
假设以下情景:
Get-ChildItem -Path . -Directory | Select-Object -ExpandProperty Name
> folder
> folder_1
> folder_2
然后(如果文件夹存在,脚本返回新名称):
$FolderName = 'folder'
D:\PShell\SO583976.ps1
> folder_3
或者(如果文件夹不存在,脚本返回相同名称):
$FolderName = 'anotherfolder'
D:\PShell\SO583976.ps1
> anotherfolder
英文:
Try a while
loop as follows:
$i = 0
$Suffix=''
while (Test-Path -Path "$FolderName$Suffix" -PathType Container) {
$i++
$suffix="_$i"
}
$FolderName = "$FolderName$Suffix"
$FolderName
Supposing the following scenario:
Get-ChildItem -Path . -Directory | Select-Object -ExpandProperty Name
> folder
> folder_1
> folder_2
then (a folder exists, script returns a new name):
$FolderName = 'folder'
D:\PShell\SO583976.ps1
> folder_3
or (a folder does not exist, script returns the same name):
$FolderName = 'anotherfolder'
D:\PShell\SO583976.ps1
> anotherfolder
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论