I'm not saying it's all dotnet’s fault, but it was when deploying dotnetcore
services to a linux VM that I thought, “what I really, really want is both bash
and powershell
setup scripts in a single file”. Surely a working incantation can be crafted from such arcane systems of quoting and escaping as the two languages offer?
½ an evening later :
# This file has a bash section followed by a powershell section, # and a shared section at the end. echo @' ' > /dev/null #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv # Bash Start -------------------------------------------------- scriptdir="`dirname "${BASH_SOURCE[0]}"`"; echo BASH. Script is running from $scriptdir # Bash End ---------------------------------------------------- # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ echo > /dev/null <<"out-null" ### '@ | out-null #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv # 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."
It relies on herestring quoting being different for each platform, as is the escape character ( \
vs `
). Readibility (ha!) is very much helped by
#comments begin with a hash
being common to both, so I can do visible dividers between the sections.
My main goal was environment variable setup before launching dotnetcore
services. Sadly the incompatible syntaxes for variables and environment:
#powershell syntax $variable="value" $env:variable2=$value
#bash syntax variable=value export variable2=value
means very little shared code inside the file, but it really cut down errors a lot just by having them in the same file. Almost-a-single-source-of-truth turned out to be much more reliable than not-at-all a single source of truth.
Bash-then-powershell
was simpler than Powershell-then-bash
. My state-of-the art is powershell named and validated parameters, which allows tab-completion to work in powershell.
` # \ # PowerShell Param # every line must end in #\ except last line must end in <#\ # And, you can't use backticks in this section #\ param( [ValidateSet('A','B')]$tabCompletionWorksHere, #\ [switch]$andHere #\ ) <#\ #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `
Repo: github.com/chrisfcarroll/PowerShell-Bash-Dual-Script-Templates
Raw: Powershell-or-bash-with-parameters .
Alternatively, do everything in powershell?
Of course, sensible people would do everything in a single scripting language. But it has been well-worth having the tools for both approaches. Especially for short bootstrap scripts.
For a powershell core everywhere approach, my main adaptation is the shebang header on all .ps1
files:
#! /usr/bin/env pwsh
which tells unix machines to what kind of script it is. Powershell itself ignores it as a comment. Finally, you must also chmod a+x *.ps1
to mark them as executable.
One thought on “Bash and PowerShell in a single script file”