PowerShell – 如果文件夹存在,则增加文件夹名称

huangapple go评论68阅读模式
英文:

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调用。
英文:

<!-- 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 &#39;_(\d+)$&#39;) { [int] $Matches.1 } else { 0 } }
  Sort-Object -Descending |
  Select-Object -First 1

if ($null -ne $highestExistingNum) { # At least 1 preexisting folder?
  $FolderName = $FolderName + &#39;_&#39; + (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-digit 0 padding (e.g., 001), use: (1 + $highestExistingNum).ToString(&#39;D3&#39;)

  • 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.
  • 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 with Sort-Object (i.e. Sort-Object -Descending -Top 1), which obviates the need for the Select-Object call.

答案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 = &#39;foo&#39;
$Target = &quot;C:\&quot;
Get-ChildItem -Path $Target -Directory `
| Where-Object { $_.Name -match &quot;$FolderName`_(\d+)|$FolderName&quot;} `
| ForEach-Object {
  if ($_ -match &quot;$FolderName`_(\d+)&quot;){
    $NewName = $FolderName + &quot;_$([int]$matches[1] + 1)&quot;
  } else {
    $NewName = $FolderName + &#39;_1&#39;
  }
  $OldName = $_.FullName
  $NewName = Join-Path $Target $NewName
  Write-Host &quot;Found &#39;$($_.FullName)&#39;, renaming to &#39;$NewName&#39;&quot;
  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 = &#39;MyDir&#39;
$FullName = $BaseName
$i = 0
while (Test-Path $FullName)
{
  $FullName = &quot;$BaseName_$i&quot;
  $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=&#39;&#39;
while (Test-Path -Path &quot;$FolderName$Suffix&quot; -PathType Container) {
    $i++
    $suffix=&quot;_$i&quot;
}
$FolderName  = &quot;$FolderName$Suffix&quot;
$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 = &#39;folder&#39;
D:\PShell\SO583976.ps1

> folder_3

or (a folder does not exist, script returns the same name):

$FolderName = &#39;anotherfolder&#39;
D:\PShell\SO583976.ps1

> anotherfolder

huangapple
  • 本文由 发表于 2023年6月30日 03:08:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76583976.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定