【问题标题】:Search and replace files and folders names with txt file support使用 txt 文件支持搜索和替换文件和文件夹名称
【发布时间】:2019-02-24 19:50:42
【问题描述】:

我有很多文件夹,里面有这些不同的文件。每个文件夹及其子文件名称相同,扩展名不同,所以ABC文件夹中有ABC.png、ABC.prj、ABC.pgw文件,DEF文件夹中有DEF.png、DEF.prj、 DEF.pgw 文件等等。 使用脚本,我创建了一个带有 png 文件名列表的 txt 文件。然后我在第 2 行中为第 1 行中的名称输入一个新名称,在第 4 行中为第 3 行中的名称输入一个新名称,依此类推。 现在我正在搜索一个powershell脚本: - 扫描所有文件夹以查找第 1 行中的名称并将其替换为第 2 行中的名称 - 扫描所有文件夹以查找第 3 行中的名称并将其替换为第 4 行中的名称,依此类推

我在下面尝试过,但它不起作用。

你有什么建议吗?谢谢

$0=0
$1=1
do {
$find=Get-Content C:\1\Srv\MapsName.txt | Select -Index $0
$repl=Get-Content C:\1\Srv\MapsName.txt | Select -Index $1
Get-ChildItem C:\1\newmaps -Recurse | Rename-Item -NewName { $_.name -replace $find, $repl} -verbose
$0=$0+2
$1=$1+2
}
until ($0 -eq "")

【问题讨论】:

  • 抱歉,我花了一些时间,但我已经出去了几天。我使用不同的方法为您的问题添加了新答案。

标签: powershell


【解决方案1】:

我认为您的代码以及 Manuel 给您的代码存在一些问题。

  1. 虽然您有一个旧文件名和新文件名列表,但您并没有在 Get-ChildItem cmdlet 中使用它,而是尝试替换它找到的所有文件。
  2. 使用-replace 使用正则表达式替换,即文件名中的特殊字符. 被视为Any Character,而不仅仅是一个点。
  3. 您正在尝试查找*.png 文件,但您没有使用Get-ChildItem cmdlet 添加-Filter,因此现在它将返回所有文件类型。

无论如何,我有一个不同的方法给你:

如果您的输入文件 C:\1\Srv\MapsName.txt 看起来像这样:

picture1.png
ABC_1.png
picture2.png
DEF_1.png
picture3.png
DEF_2.png

以下代码将使用它来构建查找哈希表,以便它可以对输入文件中提到的文件进行操作,而其他所有文件保持不变。

$mapsFile   = 'C:\1\Srv\2_MapsName.txt'
$searchPath = 'C:\1\NewMaps'

# Read the input file as an array of strings.
# Every even index contains the file name to search for. 
# Every odd index number has the new name for that file.
$lines = Get-Content $mapsFile

# Create a hashtable to store the filename to find
# as Key, and the replacement name as Value
$lookup = @{}
for ($index = 0; $index -lt $lines.Count -1; $index += 2) {
    $lookup[$lines[$index]] = $lines[$index + 1]
}

# Next, get a collection of FileInfo objects of *.png files
# If you need to get multiple extensions, remove the -Filter and add -Include '*.png','*.jpg' etc.
$files = Get-ChildItem -Path $searchPath -Filter '*.png' -File -Recurse

foreach ($file in $files) {
    # If the file name can be found as Key in the $lookup Hashtable
    $find = $file.Name
    if ($lookup.ContainsKey($find)) {
        # Rename the file with the replacement name in the Value of the lookup table
        Write-Host "Renaming '$($file.FullName)' -->  $($lookup[$find])"
        $file | Rename-Item -NewName $lookup[$find]
    }
}

编辑

如果输入文本文件 'C:\1\Srv\MapsName.txt' 不包含包含扩展名的文件名,请将最后的 foreach 循环更改为:

foreach ($file in $files) {
    # If the file name can be found as Key in the $lookup Hashtable
    # Look for the file name without extension as it is not given in the 'MapsName.txt' file.
    $find = [System.IO.Path]::GetFileNameWithoutExtension($file.Name)
    if ($lookup.ContainsKey($find)) {
        # Rename the file with the replacement name in the Value of the lookup table
        # Make sure to add the file's extension if any.
        $newName = $lookup[$find] + $file.Extension
        Write-Host "Renaming '$($file.FullName)' --> '$newName'"
        $file | Rename-Item -NewName $newName
    }
}

希望有帮助

【讨论】:

  • 谢谢。今晚我将尝试脚本。 MapsName.txt 包含如下行:423423_ABC_54 <br/> ABC 54 <br/> 895293_79_DFG <br/> DFG 112 <br/> ...
  • @Marco 我希望那些<br/> 实际上是真正的换行符!我在我的答案中添加了新代码,以处理您没有在输入文件中包含文件扩展名的事实。或许,在您第一次尝试此操作时,将-WhatIf 参数添加到Rename-Item cmdlet 是明智的。

  • 是我在上面的评论中获得换行符的证明,但没有成功:( 我编辑了这一行:$files = Get-ChildItem -Path $searchPath -Recurse | sort name -descending,一切都以超音速运行。谢谢
  • @Marco 我很高兴听到它对你有用。如果您觉得我的回答解决了您的问题,请考虑通过单击左侧的 ✓ 来投票或接受答案。这将帮助其他有类似问题的人更容易地找到它,而且作为对我的奖励,它将增加我的代表。 ;)
【解决方案2】:

你的 sn-p 的问题是它永远不会结束。 我试过了,它可以工作,但一直在循环。 我创建了一个包含文件 a.txt、b.txt 和 c.txt 的文件夹。 在 map.txt 我有这个内容:

a.txt
a2.md
b.txt
b2.md
c.txt
c2.md

运行以下脚本,我设法将每个文件重命名为符合预期。

$0=0
$1=1

$find=Get-Content D:\map.txt | Select -Index $0
while($find) {
    $find=Get-Content D:\map.txt | Select -Index $0
    $repl=Get-Content D:\map.txt | Select -Index $1

    if(!$find -Or !$repl) {
        break;
    }

    Get-ChildItem D:\Files -Recurse | Rename-Item -NewName { $_.name -replace $find, $repl} -verbose
    $0=$0+2
    $1=$1+2
}

【讨论】:

  • 像魅力一样工作!感谢您的代码和解释。
  • 我在想我的解决方案并不理想,你应该使用 while 循环,直到。在您的代码中,真正的问题是您试图停止循环检查 $0 是否等于空字符串,但这绝不是真的,因为它始终是一个永远递增的整数。所以我会更新我的答案来实现一个while循环。
  • 谢谢大家,明天我会在真实的东西上试一试。
  • 为什么这么多Get-Content。您只需要这样做一次并按索引遍历数组。像$lines = Get-Content "D:\map.txt" 这样的东西。下次用作$lines[$0]$lines[$1] 等。
  • @Theo 我无法执行您的建议,我的错误在哪里?:$0=0 $1=1 $lines=Get-Content C:\1\Srv\2_MapsName.txt while($find) { $find=$lines[$0] $repl=$lines[$1] if(!$find -Or !$repl) { break; } Get-ChildItem C:\1\NewMaps -Recurse | Rename-Item -NewName { $_.name -replace $find, $repl} #-verbose $0=$0+2 $1=$1+2 },
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-18
  • 2014-08-06
  • 2015-09-11
  • 2019-08-27
  • 2020-01-29
  • 2022-01-07
相关资源
最近更新 更多