You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PowerShell中修改路径中间节点?适配ImageMagick对比场景

用ImageMagick的SSIM算法对比图像的PowerShell脚本优化方案

目录结构

原始PNG图像与压缩后JPG图像的目录结构如下:

+ root
  |
  +- FooBar
  |  |
  |  +- 2023-10
  |  |  \- *.png
  |  \- 2023-11
  |     \- *.png
  \- FooBar.cmp
     |
     +- 2023-10
     |  \- *.jpg
     \- 2023-11
        \- *.jpg
  • root\FooBar:存储原始PNG图像
  • root\FooBar.cmp:存储压缩后的JPG图像
  • 文件名格式:FooBar_%Y-%m-%d_%H-%M-%S.<millisecond>_<display_w>x<display_h>.<extension>,其中%开头字符对应C语言strftime格式化规则,<millisecond>为毫秒值,<display_w>/<display_h>为分辨率宽高,<extension>为png或jpg

现有尝试脚本

当前使用的PowerShell脚本如下:

Get-ChildItem .\root\FooBar -Recurse -Include "*.png" | % { $new = Join-Path -Path $_.Directory.Parent.Parent.FullName -ChildPath ($_.Directory.Parent.Name + ".cmp"); $new = Join-Path -Path $new -ChildPath $_.Directory.BaseName; $new = Join-Path -Path $new -ChildPath ($_.BaseName + ".jpg"); magick compare -metric SSIM $new $_  NUL 2>&1 | % ToString }

注:2>&1 | % ToString用于规避隐式RemoteException,可忽略

需求与问题

现有脚本写法冗余,希望直接修改路径中间节点实现转换(例如将root\FooBar\2023-11\2023-11-01_02-03-04.567_890x1234.png转为root\FooBar.cmp\2023-11\2023-11-01_02-03-04.567_890x1234.jpg),需解决:

  1. PowerShell 5.1(版本信息如下)下的简洁实现方式
  2. 升级到最新PowerShell版本后的优化方案

PowerShell 5.1版本信息:

PS> $PSVersionTable

Name                           Value                                                                                                                                                                        
----                           -----                                                                                                                                                                        
PSVersion                      5.1.19041.3570                                                                                                                                                               
PSEdition                      Desktop                                                                                                                                                                      
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                                                                                      
BuildVersion                   10.0.19041.3570                                                                                                                                                              
CLRVersion                     4.0.30319.42000                                                                                                                                                              
WSManStackVersion              3.0                                                                                                                                                                          
PSRemotingProtocolVersion      2.3                                                                                                                                                                          
SerializationVersion           1.1.0.1 

解决方案

PowerShell 5.1 实现方式

利用字符串替换直接修改路径节点和后缀,是最简洁的实现方式:

# 固定应用名称的写法
Get-ChildItem .\root\FooBar -Recurse -Filter *.png | ForEach-Object {
    # 替换路径中的FooBar节点为FooBar.cmp,同时替换后缀为jpg
    $cmpPath = $_.FullName -replace '\\FooBar\\', '\FooBar.cmp\' -replace '\.png$', '.jpg'
    # 执行SSIM对比
    magick compare -metric SSIM $cmpPath $_.FullName NUL 2>&1 | ForEach-Object ToString
}

如果FooBar是动态应用名称,可先定义变量再替换:

$appName = 'FooBar' # 替换为实际应用名称
Get-ChildItem ".\root\$appName" -Recurse -Filter *.png | ForEach-Object {
    $cmpPath = $_.FullName -replace "\\$appName\\", "\\$appName.cmp\\" -replace '\.png$', '.jpg'
    magick compare -metric SSIM $cmpPath $_.FullName NUL 2>&1 | ForEach-Object ToString
}

这种写法避免了多层Join-Path嵌套,代码更直观易读。

最新PowerShell版本(7.x+)实现方式

PowerShell 7.x+对路径操作的支持更灵活,核心逻辑依然可以用字符串替换,写法与5.1一致且性能更优:

$appName = 'FooBar'
Get-ChildItem ".\root\$appName" -Recurse -Filter *.png | ForEach-Object {
    $cmpPath = $_.FullName -replace "\\$appName\\", "\\$appName.cmp\\" -replace '\.png$', '.jpg'
    magick compare -metric SSIM $cmpPath $_.FullName NUL 2>&1 | ForEach-Object ToString
}

如果偏好结构化路径拼接,也可以用更清晰的层级写法:

$appName = 'FooBar'
Get-ChildItem ".\root\$appName" -Recurse -Filter *.png | ForEach-Object {
    $rootDir = $_.Directory.Parent.Parent.FullName
    $cmpRootDir = Join-Path $rootDir "$appName.cmp"
    $targetSubDir = Join-Path $cmpRootDir $_.Directory.BaseName
    $cmpPath = Join-Path $targetSubDir ($_.BaseName + '.jpg')
    magick compare -metric SSIM $cmpPath $_.FullName NUL 2>&1 | ForEach-Object ToString
}

内容的提问来源于stack exchange,提问作者user-id-14900042

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 07:07:48