Verwandte: #6291, #6292 und #4624
Nachfassen von https://github.com/PowerShell/PowerShell/issues/6292#issuecomment -371344550:
Hinweis: Die fraglichen Token, wie -foo:bar
, _look_ like benannte PowerShell-Argumente (und werden hinter den Kulissen zunächst immer als solche geparst - siehe Kommentar von @BrucePay unten), sollten aber als übergeben werden -is (außer um eventuell den String zu erweitern) beim Aufruf externer Programme.
Token, die zufällig wie -foo.bar
aussehen, erleiden ein ähnliches Schicksal (siehe #6291).
Dies funktioniert bereits wie erwartet mit der Argumentübergabe _direct_ (z. B.
echoArgs -foo:bar
übergibt -foo:bar
als einzelnes Argument
), aber nicht beim Passieren von $Args
/ Splatting ( @Args
).
Hinweis: Das Problem ist grundlegend für die Verwendung von $Args
/ @Args
und, obwohl es vielleicht weniger verbreitet ist, betrifft es auch seine Verwendung beim Aufrufen von PowerShell-nativen Befehlen - siehe Kommentar unten .
Auf macOS oder Linux ausführen.
function baz {
bash -c 'for a; do echo $a; done' - $Args # note: same with <strong i="32">@Args</strong>
}
baz -foo:bar
'---'
baz -foo.bar
-foo:bar
---
-foo.bar
-foo:
bar
---
-foo
.bar
Die Argumente werden unerwartet in zwei Teile gebrochen. Siehe verlinkten Kommentar für Hintergrund.
PowerShell Core v6.0.1 on macOS 10.13.3
PowerShell Core v6.0.1 on Ubuntu 16.04.3 LTS
PowerShell Core v6.0.1 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Windows PowerShell v5.1.15063.674 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Hinweis: Die fraglichen Token wie -foo:bar sehen aus wie benannte PowerShell-Argumente,
@mklement0 Wie ich in den Kommentaren in #6292 beschrieben habe, _sind_ diese PowerShell-Argumente. Stets. Die Parameterbindung erfolgt lange nach Abschluss der Kompilierung. Im kompilierten AST hat das Token für -foo:
jetzt ein Flag, das anzeigt, dass im Quellcode kein Leerzeichen dahinter war. NativeCommandParameterBinder
überprüft dieses AST-Element, um zu sehen, ob das Flag gesetzt ist, und verkettet dann den Parameter und das Argument ohne Leerzeichen dazwischen. Wenn es nicht gesetzt ist, wird ein Leerzeichen eingefügt. Dies funktioniert nur, wenn die Argumente literal sind (dh NativeCommandParameter
war Zugriff auf den AST für das Argument). Im Splatting-Fall sind die Argumente Werte, keine wörtlichen Argumente, sodass Sie ein Leerzeichen erhalten.
Eine Möglichkeit, dies zu beheben, besteht darin, die Tokeneigenschaft "NoSpace" in Metadaten für den entsprechenden Zeichenfolgenwert zu übertragen. Das NativeCommandParameterBinder
könnte dann nach diesen Metadaten suchen, wenn es sein arg-Array in einen String umwandelt. Es lohnt sich wahrscheinlich, darüber nachzudenken, ob es andere Fälle (insbesondere *nix spezifische Fälle) gibt, die angegangen werden sollten.
@args
auch beim Aufrufen von PowerShell-Funktionen (nicht nur externe Programme) unterbrochen wird:Dieses Szenario zu unterstützen ist vermutlich noch schwieriger, da hier erwartet wird, dass die benannten Parameter unverändert mit ihren ursprünglichen Typen übergeben werden.
Hier ist eine vereinfachte Reproduktion:
function b {
Param
(
[Switch] $p1,
[int] $p2,
$rest
)
"`$p1: [$p1]"
"`$p2: [$p2]"
"`$rest: [$rest]"
}
& { b <strong i="9">@args</strong> } -p1:$false 666
$p1: [True] # `-p1:` was interpreted as just `-p1`
$p2: [0] # `$false`, as a separate argument, was coerced to [int] 0
$rest: [666] # what was meant to be the 2nd argument was passed as the 3rd
Die Problemumgehung – und zu Beginn die vorzuziehende Lösung – besteht darin, denselben param()
Block in der Relaying-Funktion zu definieren und mit @PSBoundParameters
splat.
Ich habe gerade die letzte Woche oder so damit verbracht, mit diesem Problem zu ringen. Nachdem ich die Parameterwerte des erzwungenen Wechsels (wie -foo:$bar
) verfolgt hatte, die nach dem Splating mit @Args
, dachte ich, dass dies ein obskures Scoping-Problem sein muss. Stellen Sie sich meine Überraschung vor, als ich entdeckte, dass das Erzwingen eines Switch-Parameterwerts auf diese Weise nicht das erwartete Verhalten hätte. Ich habe es sogar mit der Version von Powershell 7 Preview 1 getestet und das gleiche Problem tritt immer noch auf. Ich würde hoffen, dass es nach mehr als einem Jahr als bekanntes Problem behoben wird ...
Als Referenz ist dies der Test, den ich erstellt habe, um den Fehler zu zeigen. Habe es auf einem Server 2016-Computer mit Powershell 7 Preview 1 sowie auf einem Server 2012 R2-Computer mit Powershell 5.1 gesehen.
function foo
{
param(
[switch]$testArg = $false
)
write-host "Test arg value: '$testArg'"
}
function bar
{
foo <strong i="9">@Args</strong>
}
$testSplat = @{
testArg = $false
}
write-host "#### Foo tests ####"
foo
foo -testArg:$true
foo -testArg:$false
foo <strong i="10">@testSplat</strong>
write-host "#### Bar tests ####"
bar
bar -testArg:$true
bar -testArg:$false
bar <strong i="11">@testSplat</strong>
Hilfreichster Kommentar
Ich habe gerade die letzte Woche oder so damit verbracht, mit diesem Problem zu ringen. Nachdem ich die Parameterwerte des erzwungenen Wechsels (wie
-foo:$bar
) verfolgt hatte, die nach dem Splating mit@Args
, dachte ich, dass dies ein obskures Scoping-Problem sein muss. Stellen Sie sich meine Überraschung vor, als ich entdeckte, dass das Erzwingen eines Switch-Parameterwerts auf diese Weise nicht das erwartete Verhalten hätte. Ich habe es sogar mit der Version von Powershell 7 Preview 1 getestet und das gleiche Problem tritt immer noch auf. Ich würde hoffen, dass es nach mehr als einem Jahr als bekanntes Problem behoben wird ...Als Referenz ist dies der Test, den ich erstellt habe, um den Fehler zu zeigen. Habe es auf einem Server 2016-Computer mit Powershell 7 Preview 1 sowie auf einem Server 2012 R2-Computer mit Powershell 5.1 gesehen.