Lovethenakedgun
Lovethenakedgun

Reputation: 867

Powershell and CMD combining command-line filepath arguments to Python

I was making user-entered variable configurable via command line parameters & ran into this weird behaviour:

PS D:> python -c "import sys; print(sys.argv)" -imgs ".\Test V4\Rilsa\" -nl 34
['-c', '-imgs', '.\\Test V4\\Rilsa" -nl 34']

PS D:> python -c "import sys; print(sys.argv)" -imgs ".\TestV4\Rilsa\" -nl 34
['-c', '-imgs', '.\\TestV4\\Rilsa\\', '-nl', '34']

If the name of my folder is Test V4 with a space character, then all following parameters end up in the same argument element '.\\Test V4\\Rilsa" -nl 34'. There is also a trailing " quote after the directory name. I tried this again in CMD, thinking it was a Powershell quirk & experienced the same behaviour.

What's going on here? I'm assuming it has something to do with backslashes in Powershell -- though it's the default in Windows for directory paths -- but why do I get diverging behaviour depending on space characters & what's a good way to handle this assuming Windows paths are auto-completed into this form by the shell (i.e. trailing \)?

Upvotes: 1

Views: 55

Answers (1)

mklement0
mklement0

Reputation: 439777

  • You're seeing a bug in Windows PowerShell (the legacy, ships-with-Windows, Windows-only edition of PowerShell whose latest and last version is 5.1), which has since been fixed in PowerShell (Core) 7, as detailed in this answer.

  • In short, as you've since discovered yourself, the problem occurs when you pass arguments that contain space(s) and end in \ to external programs, because Windows PowerShell - when it constructs the true process command line behind the scenes - blindly encloses such arguments in "...", causing most target programs to interpret the closing \" sequence as an escaped " char.
    (Since arguments without spaces are not subject to this "..." enclosure, they are not affected.)


Workarounds (required in Windows PowerShell only, but should also work in PowerShell 7):

  • Manually add a trailing \ to your argument:

    # Note the '\\'
    python -c "import sys; print(sys.argv)" -imgs ".\Test V4\Rilsa\\" -nl 34
    
  • Alternatively, add a trailing space, relying on the fact that on Windows trailing spaces in paths are usually ignored:

    # Note the trailing space before the closing "
    python -c "import sys; print(sys.argv)" -imgs ".\Test V4\Rilsa " -nl 34
    

In either case, if the path must be passed via a variable rather than a literal and the variable value may or may not end in \, use "...", i.e. an expandable (interpolating) string, such as "$dirPath\" or "$dirPath "

Upvotes: 2

Related Questions