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.