Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

For native commands, variables are not expanded if argument begins with - (-key=$var, -D$var) #21460

Open
MatejKafka opened this issue Apr 12, 2024 · 9 comments
Labels
Needs-Triage The issue is new and needs to be triaged by a work group. WG-Engine core PowerShell engine, interpreter, and runtime WG-NeedsReview Needs a review by the labeled Working Group

Comments

@MatejKafka
Copy link

MatejKafka commented Apr 12, 2024

This issue follows up on one aspect of #6467. Many native commands use - prefix for named parameters, but either separate the parameter value with = (-param=value) or use no separator at all (e.g. GCC's -Ddefine).

Due to PowerShell parsing rules, even for native commands, anything starting with - is parsed as a possible parameter name, and PowerShell does not expand variables in suspected parameter names:

> $var = "value"
> .\GetCommandLine.exe -key=$var -D$var
"D:\test\GetCommandLine.exe" -key=$var -D$var # no expansion of $var done

This behavior surprises me each time I encounter it, especially because it often does not result in any error, just the command silently doing something wrong:

# WSL bash swallows the variable, and what is actually silently invoked is `wsl -- cmake -DCMAKE_BUILD_TYPE=`
wsl -- cmake -DCMAKE_BUILD_TYPE=$BuildType

I would argue that it would be much more intuitive to disable special parsing of arguments for native executables and treat tokens starting with - as an ordinary argument – native commands don't have a consistent way of parsing arguments, and assuming anything about the way they're parsed (except for argv splitting rules) will imo always lead to hard-to-understand edge cases.

While this would be a breaking change, I strongly suspect that it falls in Bucket 3: Unlikely Grey Area, since parameter names or values intentionally containing $ are not common in practice, and I would expect most PowerShell users to defensively escape them anyway.


GetCommandLine is the following C program, which just prints the command line exactly as it receives it:

#include <Windows.h>
#include <stdio.h>

int main() {
    wprintf(L"%ls\n", GetCommandLineW());
}
@MatejKafka MatejKafka added the Needs-Triage The issue is new and needs to be triaged by a work group. label Apr 12, 2024
@MatejKafka MatejKafka changed the title For native commands, variables are not expanded if argument begins with - (-Dkey=$var) For native commands, variables are not expanded if argument begins with - (-key=$var, -D$var) Apr 12, 2024
@237dmitry
Copy link

--key=$value parameters work. I could not find application with single -key=$value syntax

ss

@MartinGC94
Copy link
Contributor

If the language allows people to use variables in parameter names then people will start doing things like: $A = "Action"; Get-ChildItem C:\ -Error$A Ignore -Warning$A Ignore and I don't like the thought of having to deal with scripts written like that.
If you are getting surprised when a variable isn't being expanded then I'd advise you to use the syntax highlighting to your advantage.

@MatejKafka
Copy link
Author

@MartinGC94 No, I don't want this for built-in commands, where the parser unambiguously knows what is a parameter name and what is a parameter value. However, for native commands, parser cannot ever reliably know that, and it seems more intuitive to just give up and allow expanding variables everywhere instead of allowing variables in some parameter values but not others.

@MatejKafka
Copy link
Author

@237dmitry I commonly encounter this with compiler pre-processor defines (-Dname=value) and include dirs (-Ipath/to/dir). Today, I encountered this with CMake (example above).

@MatejKafka
Copy link
Author

@MartinGC94 Ad syntax highlighting, it does not help that everything except PSReadline (I tested VS Code, NeoVim and Sublime Text) highlights the variable incorrectly, as if it was expanded.

@MartinGC94
Copy link
Contributor

You can't make it work like this for native programs without affecting PowerShell commands because the parser won't know whether or not it's a native program. Maybe you could do some trickery at runtime when it knows that it's a native command but then it would be confusing behavior because the syntax highlighting would be inaccurate.
Regarding the inaccurate syntax highlighting in the editors, that's my bad. I forgot they use the wildly inaccurate textmate grammar. Maybe one day we will get a good editor for PowerShell.

@MatejKafka
Copy link
Author

MatejKafka commented Apr 12, 2024

Hmm, that's a good point, that making the parser depend on knowing if it's parsing a native command or a cmdlet is probably not feasible, and would be a big can of worms even if theoretically possible.

Nevertheless, I would still prefer if variables would be expanded everywhere, even in parameter names, in hope that no one in their right mind will actually misuse it in the way you've shown above. While I agree that it would be nice to disallow variables in parameter names, I consider it more important for variable expansion to behave consistently, following the principle of least astonishment – if users encounter ls -Error$var Ignore, I believe most will be able to correctly guess at the behavior, while the current behavior with respect to native commands (needing to quote parameters starting with -, but not parameters starting with -- or /) is unintuitive even to experienced users and easy to overlook when encountered, resulting in subtly broken scripts.

@mklement0
Copy link
Contributor

mklement0 commented Apr 12, 2024

Note that there's a number of bugs (9 as of this writing) relating to --prefixed tokens that aren't actually parameter names (many of the issues have been closed due to inactivity, but the bugs persist):

Most of them also affect calls to PowerShell commands, notably cmdlets with ValueFromRemainingArguments arguments, such as Write-Host.

In fact, the -key=$var problem has been reported before, in the context of Write-Host:

That is, Write-Host -key=$var also prints verbatim -key=$var, without expanding $var.

I can't speak to the difficulty of fixing these problems, but I imagine that it is possible.

E.g., given that key=$var and D$var aren't valid parameter names, it makes sense to treat these tokens as expandable strings instead.
(Technically, you can do something like & { param(${D$var}) ${D$var} } foo, with positional binding, but you could never target this parameter by name, so I don't think that's a concern).


Also: 7.3 unfortunately, introduced a new problem relating to use of , that affects native programs only, however:

GitHub
PowerShell for every system! Contribute to PowerShell/PowerShell development by creating an account on GitHub.

@SteveL-MSFT
Copy link
Member

The workaround is to use quotes around the variable:

/bin/echo -d"$var"
/bin/echo -d="$var"

@SteveL-MSFT SteveL-MSFT added WG-Engine core PowerShell engine, interpreter, and runtime WG-NeedsReview Needs a review by the labeled Working Group labels Apr 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs-Triage The issue is new and needs to be triaged by a work group. WG-Engine core PowerShell engine, interpreter, and runtime WG-NeedsReview Needs a review by the labeled Working Group
Projects
None yet
Development

No branches or pull requests

5 participants