You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Command line parsing bug: spaces and trailing backslash #4358
Auto-completion uses this format with a trailing backslash, so it's expected to work correctly.
Expected behavior
.\test1\
.\test 2\
.\test1\
Actual behavior
.\test1\
.\test 2" .\test1\
Environment data
>$PSVersionTable
Name Value
---------
PSVersion 6.0.0-beta
PSEdition Core
GitCommitId v6.0.0-beta.4
OS Microsoft Windows 10.0.14393
Platform Win32NT
PSCompatibleVersions {1.0,2.0,3.0,4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
This is only indirectly related to IntelliSense (which suggests passing the arguments like that).
The real issue is how the command line is rebuilt behind the scenes by PowerShell:
Argument list .\test1\ '.\test 2\' .\test1\ is translated to .\test1\ ".\test 2\" .\test1\ behind the scenes, which any external utility that uses \ as the escape character (most of them) parses as demonstrated in the initial post, causing the initial argument partitioning to be misinterpreted:
The 2nd " in ".\test 2\", due to being preceded by \ is interpreted as an escaped", causing the remainder of the string - despite a then-missing closing " to be interpreted as part of the same argument.
The - cumbersome - workaround on Windows is to add an extra \, though, given that PowerShell does re-quoting behind the scenes (as is necessary on Windows), the fix is to let PowerShell do that automatically:
> .\ps-args-test.exe .\test1\ '.\test 2\\' .\test1\ # Note the '\\'
The - proper, hopefully-soon - fix on Unix platforms is to pass the arguments as an array of literals to the target utility, as is the norm on Unix platforms, bypassing such issues altogether. (Re-quoting behind the scenes is unnecessary on Unix platforms and should be avoided altogether.)
I'd argue it's common since it happens every time I auto-complete a directory name with a space unless I remove the trailing slash manually. My example was a bit incomplete I think, since the extra quote is also inserted with just one argument.
PS X:\scratch> .\ps-args-test.exe'.\test 2\'
.\test 2"
A shell that has a broken auto-complete for directories is... inconvenient.
Reacted by Michael Klement, Byte Northbridge and Andrew Tapia
The - cumbersome - workaround on Windows is to add an extra , though, given that PowerShell does re-quoting behind the scenes (as is necessary on Windows), the fix is to let PowerShell do that automatically:
.\ps-args-test.exe .\test1\ '.\test 2\' .\test1\ # Note the '\'
I'm trying to do this fix now but having some trouble figuring out the reasonable behavior handling the trailing backslashes of an arg string. When the arg string needs to be quoted, the trailing backslashes will escape each other and if there are odd number of backslashes, then the closing quote will be misinterpreted, for example:
PS>testexe.exe-echoargs 'test \'
Arg 0 is <test ">PS> testexe.exe -echoargs 'test \\'Arg 0 is <test \>PS> testexe.exe -echoargs 'test \\\'Arg 0 is <test \">
PS>testexe.exe-echoargs 'test \\\\'
Arg 0 is <test \\>
Now, we think the resulting " is confusing, and the ending \ should be preserved when passing to the native command. As a result, we will see behaviors like this:
PS>testexe.exe-echoargs 'test \'
Arg 0 is <test \>
PS>testexe.exe-echoargs 'test \\'
Arg 0 is <test \>
PS>testexe.exe-echoargs 'test \\\'
Arg 0 is <test \\>
PS>testexe.exe-echoargs 'test \\\\'
Arg 0 is <test \\>
You can see that when there is an odd number of backslashes, the ending backslash will be preserved, which makes the odd number of trailing backslashes always behave as (odd number + 1) trailing backslashes. Does this look like a reasonable behavior?
My sense is that once this RFC proposal by TSlivede is implemented, it will cover this scenario too, so we probably don't need a separate fix for this specific issue.
Yes, that's true. My RFC-Proposal (or any other fix for #1995) should also fix this. Basically we could rename #1995 to something like "Arguments for external executables aren't correctly escaped". In that case this issue could be closed as duplicate.
I'm separating this out from the uber issue of args to native commands which might be resolved by a future corefx api. I'll see if there is something we can do to solve this one sooner.
This bug causes all kinds of problem in Jenkins builds. Trying to set any ENV variable to a path that ends in a backslash causes this.
For example, if you try to call setx 'MY_PATH' 'C:\folder1\folders' /M;
It ends up setting MYPATH to "C:\folder1\folder2" /M"
So instead of the value ending in a backslash, it ends with a double quote, a space, a forward slash, and a capital M. I happen to be setting a SignalFx environment home path, so it ends up crashing the entire profiler process.
It doesn't get more wrong that that. And Jenkins is just tied to this Powershell version (v5.1.19041.1023) so there's no fixing it. Just literally cannot pass any Powershell arguments using single quotes when the string ends in a backslash.
The PSReadline dependency implicated here is the same problematic project that prevents more than 50 characters from being pasted into docker container when powershell is active (works fine when basic cmd.exe is active instead) to this very day.
Activity
mklement0 commentedon Jul 28, 2017
Ilya (@iSazonov):
This is only indirectly related to IntelliSense (which suggests passing the arguments like that).
The real issue is how the command line is rebuilt behind the scenes by PowerShell:
Argument list
.\test1\ '.\test 2\' .\test1\is translated to.\test1\ ".\test 2\" .\test1\behind the scenes, which any external utility that uses\as the escape character (most of them) parses as demonstrated in the initial post, causing the initial argument partitioning to be misinterpreted:"in".\test 2\", due to being preceded by\is interpreted as an escaped", causing the remainder of the string - despite a then-missing closing"to be interpreted as part of the same argument.The - cumbersome - workaround on Windows is to add an extra
\, though, given that PowerShell does re-quoting behind the scenes (as is necessary on Windows), the fix is to let PowerShell do that automatically:The - proper, hopefully-soon - fix on Unix platforms is to pass the arguments as an array of literals to the target utility, as is the norm on Unix platforms, bypassing such issues altogether. (Re-quoting behind the scenes is unnecessary on Unix platforms and should be avoided altogether.)
cc Steve Lee (@SteveL-MSFT)
SteveL-MSFT commentedon Jul 28, 2017
Unless I hear otherwise, this doesn't seem to be a common use case. I think we can fix in 6.1.0 unless someone from the community submits a PR.
akervinen commentedon Jul 30, 2017
I'd argue it's common since it happens every time I auto-complete a directory name with a space unless I remove the trailing slash manually. My example was a bit incomplete I think, since the extra quote is also inserted with just one argument.
A shell that has a broken auto-complete for directories is... inconvenient.
SteveL-MSFT commentedon Jul 30, 2017
Aleksi Kervinen (@akervinen) I see, every time with a space is definitely a concern
6 remaining items
JVimes commentedon Sep 12, 2017
Just lost an hour wondering why git status wouldn't work with -C. And a number of RoboCopy folks lost time to it.
This use case gets hit!
daxian-dbw commentedon Sep 19, 2017
Michael Klement (@mklement0) Do you think we should do this fix for now or shall we wait until https://github.com/dotnet/corefx/issues/23592 is addressed?
I'm trying to do this fix now but having some trouble figuring out the reasonable behavior handling the trailing backslashes of an arg string. When the arg string needs to be quoted, the trailing backslashes will escape each other and if there are odd number of backslashes, then the closing quote will be misinterpreted, for example:
Now, we think the resulting
"is confusing, and the ending\should be preserved when passing to the native command. As a result, we will see behaviors like this:You can see that when there is an odd number of backslashes, the ending backslash will be preserved, which makes the odd number of trailing backslashes always behave as (odd number + 1) trailing backslashes. Does this look like a reasonable behavior?
mklement0 commentedon Sep 19, 2017
Dongbo Wang (@daxian-dbw):
My sense is that once this RFC proposal by TSlivede is implemented, it will cover this scenario too, so we probably don't need a separate fix for this specific issue.
For background, see #1995 (comment)
TSlivede commentedon Sep 19, 2017
Yes, that's true. My RFC-Proposal (or any other fix for #1995) should also fix this. Basically we could rename #1995 to something like "Arguments for external executables aren't correctly escaped". In that case this issue could be closed as duplicate.
SteveL-MSFT commentedon Sep 19, 2017
TSlivede makes sense. Dupe of #1995
SteveL-MSFT commentedon Oct 1, 2017
I'm separating this out from the uber issue of args to native commands which might be resolved by a future corefx api. I'll see if there is something we can do to solve this one sooner.
triynko commentedon Sep 21, 2021
This bug causes all kinds of problem in Jenkins builds. Trying to set any ENV variable to a path that ends in a backslash causes this.
For example, if you try to call setx 'MY_PATH' 'C:\folder1\folders' /M;
It ends up setting MYPATH to "C:\folder1\folder2" /M"
So instead of the value ending in a backslash, it ends with a double quote, a space, a forward slash, and a capital M. I happen to be setting a SignalFx environment home path, so it ends up crashing the entire profiler process.
It doesn't get more wrong that that. And Jenkins is just tied to this Powershell version (v5.1.19041.1023) so there's no fixing it. Just literally cannot pass any Powershell arguments using single quotes when the string ends in a backslash.
The PSReadline dependency implicated here is the same problematic project that prevents more than 50 characters from being pasted into docker container when powershell is active (works fine when basic cmd.exe is active instead) to this very day.