1

I need to run bash commands under Powershell using Cygwin's bash.

I faced the issue that Powershell 5 and 7 processes double quotes in different way.

I'd like to have bash script working in both. Can I set up both Powershell to make them processing quotes in the same way? Or another way to have export MYKEY="MYVALUE" with double quotes in Cygwin?

Powershell 5:

PS D:\work> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      22621  3958

PS D:\work> C:\cygwin64\bin\bash.exe -l -c 'key=MYKEY; value=MYVALUE; echo export $key="$value";'
export MYKEY=MYVALUE

PS D:\work> C:\cygwin64\bin\bash.exe -l -c 'key=MYKEY; value=MYVALUE; echo export $key=\"$value\";'
export MYKEY=MYVALUE

PS D:\work> C:\cygwin64\bin\bash.exe -l -c 'key=MYKEY; value=MYVALUE; echo export $key=\\\"$value\\\";'
export MYKEY="MYVALUE"

Powershell 7:

PS D:\work> $PSVersionTable.PSVersion

Major  Minor  Patch  PreReleaseLabel BuildLabel
-----  -----  -----  --------------- ----------
7      4      4

PS D:\work> C:\cygwin64\bin\bash.exe -l -c 'key=MYKEY; value=MYVALUE; echo export $key="$value";'
export MYKEY=MYVALUE

PS D:\work> C:\cygwin64\bin\bash.exe -l -c 'key=MYKEY; value=MYVALUE; echo export $key=\"$value\";'
export MYKEY="MYVALUE"

PS D:\work> C:\cygwin64\bin\bash.exe -l -c 'key=MYKEY; value=MYVALUE; echo export $key=\\\"$value\\\";'
export MYKEY=\"MYVALUE\"

1 Answer 1

3

It is PowerShell (Core) 7's behavior that is correct, specifically in v7.3+, which corrected a long-standing bug that still affects Windows PowerShell - see this answer for details.

You can instruct PowerShell 7.3+ to exhibit the old, broken behavior via the $PSNativeCommandArgumentPassing preference variable, by setting it to 'Legacy':

Therefore, the following snippet makes the bash.exe call exhibit the same behavior in both PowerShell editions:

if ($IsCoreCLR) { $PSNativeCommandArgumentPassing = 'Legacy' }
C:\cygwin64\bin\bash.exe -l -c 'key=MYKEY; value=MYVALUE; echo export $key=\\\"$value\\\";'

# Alternatively, with a specific version check, which also avoids
# strict-mode problems, given that the $IsCoreCLR variable isn't defined
# in Windows PowerShell:
if ($PSVersionTable.PSVersion -ge '7.3') { $PSNativeCommandArgumentPassing = 'Legacy' }
C:\cygwin64\bin\bash.exe -l -c 'key=MYKEY; value=MYVALUE; echo export $key=\\\"$value\\\";'

Note:

  • You may choose to simply unconditionally set $PSNativeCommandArgumentPassing = 'Legacy', given that Windows PowerShell will just ignore it.

  • If you want to scope the effect of setting $PSNativeCommandArgumentPassing, so as to limit it to specific commands, you can enclose the latter in a script block ({ ... }) and invoke that with &, the call operator, which runs the enclosed code in a child scope, so that a scope-local copy of $PSNativeCommandArgumentPassing is created, without affecting the caller's copy.

    # Enclosure in & { ... } scopes the effect of setting 
    # $PSNativeCommandArgumentPassing
    # The caller's original value remains in effect after execution
    # of the script block.
    & {
      $PSNativeCommandArgumentPassing = 'Legacy'
      C:\cygwin64\bin\bash.exe -l -c 'key=MYKEY; value=MYVALUE; echo export $key=\\\"$value\\\";'
    }
    
Sign up to request clarification or add additional context in comments.

3 Comments

if someone is looking for a way to make this work in Windows PowerShell as well as pwsh - might have a look at this (related) answer: stackoverflow.com/a/59681993/2279385
@mwallner, this answer is specifically designed to work in both PowerShell editions.
I see, sorry / should have read the whole thing before x_x / have my upvote :-D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.