Is it possible to write one script that runs in bash/shell and PowerShell? Is it possible to write one script that runs in bash/shell and PowerShell? powershell powershell

Is it possible to write one script that runs in bash/shell and PowerShell?


It is possible; I don't know how compatible this is, but PowerShell treats strings as text and they end up on screen, Bash treats them as commands and tries to run them, and both support the same function definition syntax. So, put a function name in quotes and only Bash will run it, put "exit" in quotes and only Bash will exit. Then write PowerShell code after.

NB. this works because the syntax in both shells overlaps, and your script is simple - run commands and deal with variables. If you try to use more advanced script (if/then, for, switch, case, etc.) for either language, the other one will probably complain.

Save this as dual.ps1 so PowerShell is happy with it, chmod +x dual.ps1 so Bash will run it

#!/bin/bashfunction DoBashThings {    wget http://www.example.org/my.script -O my.script    # set a couple of environment variables    export script_source=http://www.example.org    export some_value=floob    # now execute the downloaded script    bash ./my.script}"DoBashThings"  # This runs the bash script, in PS it's just a string"exit"          # This quits the bash version, in PS it's just a string# PowerShell code here# --------------------Invoke-WebRequest "http://www.example.org/my.script.ps1" -OutFile my.script.ps1$env:script_source="http://www.example.org"$env:some_value="floob"PowerShell -File ./my.script.ps1

then

./dual.ps1

on either system.


Edit: You can include more complex code by commenting the code blocks with a distinct prefix, then having each language filter out its own code and eval it (usual security caveats apply with eval), e.g. with this approach (incorporating suggestion from Harry Johnston ):

#!/bin/bash#posh $num = 200#posh if (150 -lt $num) {#posh   write-host "PowerShell here"#posh }#bash thing="xyz"#bash if [ "$thing" = "xyz" ]#bash then#bash echo "Bash here"#bash fifunction RunBashStuff {    eval "$(grep '^#bash' $0 | sed -e 's/^#bash //')"}"RunBashStuff""exit"((Get-Content $MyInvocation.MyCommand.Source) -match '^#posh' -replace '^#posh ') -join "`n" | Invoke-Expression


While the other answer is great
(thank you TessellatingHeckler and Harry Johnston)

We can actually do way better

  1. Work with more shells (e.g. work for Ubuntu's dash)
  2. Less likely to break in future situations
  3. No need to waste processing time re-reading/evaling the script
  4. Waste less characters/lines on confusing syntax
    (we can get away with a mere 26 chars, and mere 3 lines)
  5. Even Keep syntax highlighting functional

Copy Paste Code

#!/usr/bin/env shtrue --% ; : '<#'## sh part#echo "hello from bash/dash/zsh"echo "do whatver you want just dont use #> directly"echo "e.g. do #""> or something similar"# end bash partexit #>## powershell part#echo "hello from powershell"echo "you literally don't have to escape anything here"

How? (its actually simple)

Syntax highlighting tells us almost the whole story

Powershell Highlighting

The lime green parts (the ; : ') are just arguments
The light blue is special
The <# is the start of a commententer image description here

Bash Highlighting

For bash its totally different.
The --% isn't special, its just an argument (true ignores arguments)
But the ; is special, thats the end of the command
Then : is actually the "do nothing" shell command
Then the ' starts a string argument that ends on the next line
enter image description here

Wait so how does it work?

Well it works thanks to

  • Powershell's stop parsing arg (the --%) which lets us not start a string in powershell, while starting a string inside bash
  • Bash's do-nothing command and multi line quotes
  • Powershell's multi-line comments <# and #>

Caveats?

Almost almost none. Powershell legitimately has no downside. The Bash caveats are easy to fix, and are exceedingly rare

  1. If you need #> in a bash string, you'll need to escape it somehow.
    changing "#>" to "#"">"
    or from ' blah #> ' to ' blah #''> '.
  2. If you have a comment #> and for some reason you CANNOT change that comment (this is what I mean by exceedingly rare), you can actually just use #>, you just have to add re-add those first two lines (eg true --% etc) right after your #> comment
  3. One even more exceedingly rare case is where you are using the # to remove parts of a string (I bet most don't even know this is a bash feature). Example code belowhttps://man7.org/linux/man-pages/man1/bash.1.html#EXPANSION
var1=">blah"echo ${var1#>}# ^ removes the > from var1

To fix this one, well there are alternative ways of removeing chars from the begining of a string, use them instead.