PS外壳和cmd.exe外壳的不同结果



此PowerShell代码在PS shell和cmd.exe shell中运行时似乎具有不同的结果。这些运行在 Windows 7 专业版上运行。

PS C:srctrd> $PSVersionTable.PSVersion
Major  Minor  Build  Revision
-----  -----  -----  --------
5      0      10586  117
PS C:srctrd> Get-Content .prodlist.txt
123
456
789
345
221
PS C:srctrd> Get-Content .rd2.ps1
$orgfile = 'photo.main.jpg'
$prodfile = '.prodlist.txt'
$replpat = '[^.]*(.*)','$1'
Get-Content -PSPath $prodfile |
    ForEach-Object {
        $orgfile -replace $replpat | Out-Null
        Copy-Item -Path $orgfile -Destination "$_$($matches[1])" -WhatIf
    }
PS C:srctrd> .rd2.ps1
What if: Performing the operation "Copy File" on target "Item: C:srctrdphoto.main.jpg Destination: C:srctrd123.main.jpg".
What if: Performing the operation "Copy File" on target "Item: C:srctrdphoto.main.jpg Destination: C:srctrd456.main.jpg".
What if: Performing the operation "Copy File" on target "Item: C:srctrdphoto.main.jpg Destination: C:srctrd789.main.jpg".
What if: Performing the operation "Copy File" on target "Item: C:srctrdphoto.main.jpg Destination: C:srctrd345.main.jpg".
What if: Performing the operation "Copy File" on target "Item: C:srctrdphoto.main.jpg Destination: C:srctrd221.main.jpg".

这是预期的结果。

但是,在 cmd.exe shell 中运行时,$matches变量似乎不会保留到下一条语句中。

C:>powershell -NoProfile -Command $PSVersionTable.PSVersion
Major  Minor  Build  Revision
-----  -----  -----  --------
5      0      10586  117
17:12:41.25  C:srctrd
C:>powershell -NoProfile -File .rd2.ps1
Cannot index into a null array.
At C:srctrdrd2.ps1:8 char:52
+ ...        Copy-Item -Path $orgfile -Destination "$_$($matches[1])" -What ...
+                                                       ~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray
What if: Performing the operation "Copy File" on target "Item: C:srctrdphoto.main.jpg Destination: C:srctrd123".
Cannot index into a null array.
At C:srctrdrd2.ps1:8 char:52
+ ...        Copy-Item -Path $orgfile -Destination "$_$($matches[1])" -What ...
+                                                       ~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray
What if: Performing the operation "Copy File" on target "Item: C:srctrdphoto.main.jpg Destination: C:srctrd456".
...

当我转向Windows 10系统时,我在PowerShell中使用以下命令具有相同的失败结果:

5.1.15063..674 PS shell
5.1.15063..674 cmd.exe shell
6.0.0.beta8 PS shell

为什么 $matches 变量在下一条语句中无效?为什么这在 PS 外壳和 cmd.exe 外壳中的执行方式不同?

我无法解释这种行为,但为什么要首先采取如此复杂的方法?像这样的事情会更清晰、更直接:

$suffix = $orgfile -replace '^[^.]*'
Get-Content $prodfile | ForEach-Object {
    Copy-Item -Path $orgfile -Destination "${_}${suffix}" -WhatIf
}

或者,如果您希望在循环内使用定义为变量的搜索和替换字符串进行替换,则如下所示:

$pattern     = '^[^.]*'
$replacement = ''
Get-Content $prodfile | ForEach-Object {
    $suffix = $orgfile -replace $pattern, $replacement
    Copy-Item -Path $orgfile -Destination "${_}${suffix}" -WhatIf
}

就像@AnsgarWiechers答案一样,这并不能解释不同PowerShell环境中的不同行为。但是,它确实显示了有效的内容。

核心问题是使用-replace而不是-match。使用-match将起作用,但 Ansgar 是正确的,这项工作最好在处理内容之前完成一次。

$orgfile = 'photo.main.jpg'
$prodfile = '.prodlist.txt'
$replpat = '[^.]*(.*)'
Get-Content -PSPath $prodfile |
    ForEach-Object {
        $orgfile -match $replpat | Out-Null
        Copy-Item -Path $orgfile -Destination "$_$($matches[1])" -WhatIf
    }

最新更新