While working on a new bash script, I discovered a pretty annoying difference between Kinsta and WP Engine’s SSH access. It involves sending arguments to a remote script. That’s something which is core to most of the scripts I write, like within my migration script. To demonstrate the bug I’ll start with a sample script named arguments.sh
.
#!/bin/bash
#
# Arguments sample script
#
# `arugments.sh --domain=<domain> --id=<id> --author=<author-name> --author_uri=<author_uri>`
#
# Loop through all arguments and output
for arg in "$@"; do
echo "Arg: $arg"
done
So nothing fancy, just a simple script which will output any argument you supply. The big quirk is how Kinsta and WP Engine behave when running this script remotely via over SSH as shown here.
ssh sitename@sitename.ssh.wpengine.net "bash -s -- --domain=anchor.host --author=\"Austin Ginder\"" < arguments.sh
WP Engine outputs broken:
Arg: --domain=anchor.host
Arg: --author=Austin
Arg: Ginder
Kinsta outputs properly:
Arg: --domain=anchor.host
Arg: --author=Austin Ginder
It’s appears WP Engine’s SSH is expanding all arguments which removes the quotes and breaks apart any argument values containing a space. This can be fixed for WP Engine by double wrapping the arguments like this.
ssh sitename@sitename.ssh.wpengine.net "bash -s -- --domain=anchor.host --author=\\\"\"Austin Ginder\\\"\"" < arguments.sh
However on Kinsta this means the values will be include the extra quotes.
Arg: --domain=anchor.host
Arg: --author="Austin Ginder"
In order to produce consistent results, my workaround is to double-wrap the quotes and remove any extra quotes from the argument values if found. So the full script with argument processing would look like this.
#!/bin/bash
#
# Arguments sample script
#
# `arugments.sh --domain=<domain> --id=<id> --author=<author-name> --author_uri=<author_uri>`
#
# Loop through arguments and separate regular arguments from flags
for arg in "$@"; do
# Add to arguments array. (Does not starts with "--")
if [[ $arg != --* ]]; then
count=1+${#arguments[*]}
arguments[$count]=$arg
continue
fi
# Remove leading "--"
flag_name=$( echo $arg | cut -c 3- )
# Add to flags array
count=1+${#flags[*]}
flags[$count]=$arg
# Process flags without data (Assign to variable)
if [[ $arg != *"="* ]]; then
flag_name=${flag_name//-/_}
declare "$flag_name"=true
fi
# Process flags with data (Assign to variable)
if [[ $arg == *"="* ]]; then
flag_value=$( echo $flag_name | perl -n -e '/.+?=(.+)/&& print $1' ) # extract value
flag_name=$( echo $flag_name | perl -n -e '/(.+?)=.+/&& print $1' ) # extract name
flag_name=${flag_name/-/_}
# Remove first and last quote if found
flag_value="${flag_value%\"}"
flag_value="${flag_value#\"}"
declare "$flag_name"="$flag_value"
continue
fi
done
echo "Domain: $domain"
echo "Author: $author"
This script will now output the same thing on both platforms.
Domain: anchor.host
Author: Austin Ginder
You might be thinking that double wrapping everything seems like overkill. Well, it’s not a big deal if you use an SSH wrapper script. With my toolkit CaptainCore here are some example of commands which utilizes an SSH wrapper. Under the hood all arguments being sent to the remote are double wrapped in order to play nice with Kinsta and WP Engine.
captaincore ssh sitename --script=deploy-fathom --tracker=<tracker-domain> --id=<site-id> --branding_author=<captaincore_branding_author> --branding_author_uri=<captaincore_branding_author_uri> --branding_slug=<captaincore_branding_slug>
captaincore ssh sitename --script=deploy-mailgun --key=<key> --domain=<domain>
captaincore ssh sitename --script=verify-google-analytics-takeover --verifycode=<verifycode> --uacode=<uacode> --email=<email>