Skip to content

Instantly share code, notes, and snippets.

@chrisfcarroll
Last active August 23, 2023 11:41
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chrisfcarroll/636458b42793cd453a68b529ff53b469 to your computer and use it in GitHub Desktop.
Save chrisfcarroll/636458b42793cd453a68b529ff53b469 to your computer and use it in GitHub Desktop.
Hold both bash and PowerShell code in a single script file and/or make a PowerShell.ps1 script executable on all platforms. For Windows, *nix, linux and macOs. See Comments below
` # \
# PowerShell Param statement : every line must end in #\ except the last line must with <#\
# And, you can't use backticks in this section #\
param( [ValidateSet('A','B')]$tabCompletionWorksHere, #\
[switch]$andHere #\
) <#\
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# Bash Start ------------------------------------------------------------
scriptdir="`dirname "${BASH_SOURCE[0]}"`";
echo BASH. Script is running from $scriptdir
# Bash End --------------------------------------------------------------
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
echo > /dev/null <<"out-null" ###
'@ | out-null
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# Powershell Start ----------------------------------------------------#>
$scriptdir=$PSScriptRoot
Write-host "Powershell. This script is running from $scriptdir."
# Powershell End -------------------------------------------------------
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
out-null
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# Both Bash and Powershell run the rest but with limited capabilities
echo "Some lines work in both bash and powershell."
echo "Powershell picked up the named parameter '$'tabCompletionWorksHere=$tabCompletionWorksHere '$'andHere=$andHere"
echo "Whilst bash got positional parameters \$1=$1 and \$2=$2"
# This file has a bash section followed by a powershell section,
# as well as shared sections.
echo @'
' > /dev/null
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# Bash Start -----------------------------------------------------------
scriptdir="`dirname "${BASH_SOURCE[0]}"`";
echo BASH. Script is running from $scriptdir
# Bash End -------------------------------------------------------------
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
echo > /dev/null <<"out-null" ###
'@ | out-null
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# Powershell Start -----------------------------------------------------
$scriptdir=$PSScriptRoot
"powershell. Script is running from $scriptdir"
# Powershell End -------------------------------------------------------
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
out-null
echo "Some lines work in both bash and powershell. Calculating scriptdir=$scriptdir, requires separate sections."
#! /usr/local/bin/pwsh
# A single Powershell file can be recognised as executable on all platforms: Windows, linux & macOs
@"
This file is PowerShell only, but it can run unmodified on Windows, linux & macOs
Windows recognises it as executable because of the the ps1 suffix.
linux and macOs recognises the #! header and so will pass the script to powershell to run.
linux and macOs do still require the execute bit set: chmod a+x *.ps1
"@
[System.Environment]::OSVersion
# This file has a powershell section first followed by the bash section,
# as well as shared sections. But it is more complicated. Putting the
# the bash section first, followed by powershell, is simpler.
# ----------------------------------------------------------------------
echo @"
" > /dev/null ; echo > /dev/null <<"out-null" ###
"@ | out-null
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# Powershell Start -----------------------------------------------------
$scriptdir=$PSScriptRoot
"powershell. Script is running from $scriptdir"
# Powershell End -------------------------------------------------------
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
out-null
echo @'
' > /dev/null
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# Bash Start -----------------------------------------------------------
scriptdir="`dirname "${BASH_SOURCE[0]}"`";
echo BASH. Script is running from $scriptdir
# Bash End -------------------------------------------------------------
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
echo > /dev/null <<out-null
'@ | out-null
out-null
# ------------------------------------------------------
echo "Some lines work in both bash and powershell. Calculating scriptdir=$scriptdir, requires separate sections."
@chrisfcarroll
Copy link
Author

chrisfcarroll commented Oct 7, 2017

  • Don't forget that to make anything executable in bash, you must chmod —e.g. chmod a+x script.ps1—to set the executable flag.
  • Bash-first seems simpler than powershell-first.
  • I am particularly pleased that it is possible to have PowerShell tab-completion for parameters working in a script file that also runs on bash :-)
  • Tip: if your editor lets you switch syntax, then switch between PowerShell and Bash highlighting for editing each section. Sublime Text makes this easy with the syntax button in the bottom right corner of the window.
  • There are pros and cons to keeping bash and powershell versions of code. It is still code duplication. I have tended
    to do this:
    • For setting the environment, I use Bash-or-Powershell.ps1 or Bash-or-PowerShell-with-Param.ps1 and write the duplicated environment setup for the two shells. The same dot-source syntax, . scriptthatsetsenvironmentvariables.ps1 then works in both shells.
    • For executing commands, it's simpler to write-once in PowerShell and use the Powershell-executable-on-win-and-nix.ps1 template.
    • Write-once in bash is an option of course. But PowerShell is 30 years newer than bash. It shows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment