patternbashMinor
Connecting to EC2 instances using the instance name instead of IP
Viewed 0 times
theinstancesconnectingec2instanceinsteadnameusing
Problem
I'm an intensive user of AWS EC2 instances, many instances are launched, stopped, repurposed, etc.
To connect to any instance using
The bash script I wrote (following the question I asked on SO) uses
Here is the main code, including the auto-completion code:
The main function (
The auto-completion command (
A small helper command (
Since this is the first function I've written in bash, I would love to hear some opinions on the code, style
To connect to any instance using
SSH I must keep track of their IPs.The bash script I wrote (following the question I asked on SO) uses
aws-cli to do the heavy lifting for me, leaving me to remember only the logical names I've given to my instances.Here is the main code, including the auto-completion code:
# connect to machine
function sash {
if [ -z $1 ]; then
echo "Please enter machine name"
return 1
fi
local instance ip pem
instance=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=$1" "Name=instance-state-name,Values=running" --query 'Reservations[*].Instances[].[KeyName,PublicIpAddress]' --output text)
if [ -z "${instance}" ]; then
echo Could not find an instance named $1
return 1
else
ip=$(echo $instance | awk '{print $2}')
pem=$(echo $instance | awk '{print $1}')
echo "Connecting to $1 ($ip)"
ssh -i ~/.aws/$pem.pem ubuntu@$ip
fi
}
function clear_sash {
unset -v _sash_instances
}
# completion command
function _sash {
if [ -z "${_sash_instances}" ]; then
_sash_instances="$( aws ec2 describe-tags --filter Name=key,Values=Name Name=resource-type,Values=instance --query Tags[].Value --output text )"
fi
local curw
COMPREPLY=()
curw=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=($(compgen -W "${_sash_instances}" -- $curw))
return 0
}
complete -F _sash sashThe main function (
sash) takes the first parameter, and queries aws ec2 for a machine with a 'Name' tag with that value, extracts its public ip and pem file, and calls the proper ssh command.The auto-completion command (
_sash) enumerates the names of all EC2 machines, and keeps them in a cache in the scope of the shell.A small helper command (
clear_sash) is used to clear the cache for the auto-complete.Since this is the first function I've written in bash, I would love to hear some opinions on the code, style
Solution
It's mostly fine, but I would suggest some minor improvements.
Give a proper name to
You use it in several places later and it will make the code more readable.
Instead of this:
you can use
This is a bit ugly:
It's ugly because you're spawning two
Or perhaps slightly cleaner to read into an array:
The array solution is especially good if the indexes of ip and pem are dynamic, for example if they come from variables:
(It would be cleaner to have the
For the record, here's my earlier uglier
This is not as good as
In this code:
The first
Also, I think it's better to write
Actually, since the line fits within 80 characters, I'm not sure I would use the local
The final
Give a proper name to
$1 early on, for example:host=$1
if [ -z $host ]; then
echo "Please enter machine name"
return 1
fiYou use it in several places later and it will make the code more readable.
Instead of this:
if [ -z "${instance}" ]; thenyou can use
[[ ... ]] instead and drop the double quotes:if [[ -z $instance ]]; thenThis is a bit ugly:
ip=$(echo $instance | awk '{print $2}')
pem=$(echo $instance | awk '{print $1}')It's ugly because you're spawning two
awk processes for the same input. You could use a single read instead:read pem ip junk <<< $instanceOr perhaps slightly cleaner to read into an array:
read -a arr <<< $instance
ip=${arr[1]}
pem=${arr[0]}The array solution is especially good if the indexes of ip and pem are dynamic, for example if they come from variables:
read -a arr <<< $instance
# given: ip_idx=2 and pem_idx=1
ip=${arr[$ip_idx - 1]}
pem=${arr[$pem_idx - 1]}(It would be cleaner to have the
*_idx 0-based, but I used this example for the sake of illustrating simple arithmetics in array indexes.)For the record, here's my earlier uglier
awk solution:set -- $(awk '{print $1, $2}' <<< $instance)
pem=$1
ip=$2This is not as good as
read, because it spawns an awk process, and it overwrites the positional parameters $1, $2, ... Other variants using $pem_idx and $ip_idx:set -- $(awk "{print \$pem_idx, \$ip_idx}" <<< $instance)
# or:
set -- $(awk -v ip_idx=$ip_idx -v pem_idx=$pem_idx '{print $(pem_idx), $(ip_idx)}' <<< $instance)In this code:
local curw
COMPREPLY=()
curw=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=($(compgen -W "${_sash_instances}" -- $curw))The first
COMPREPLY=() is unnecessary because you overwrite it soon after anyway.Also, I think it's better to write
local on the same line as the assignment:local curw=${COMP_WORDS[COMP_CWORD]}Actually, since the line fits within 80 characters, I'm not sure I would use the local
curw at all:COMPREPLY=($(compgen -W "${_sash_instances}" -- ${COMP_WORDS[COMP_CWORD]}))The final
return 0 is unnecessary if the last operation is successful. If the last operation is not successful, you probably want to let the function return failure anyway.Code Snippets
host=$1
if [ -z $host ]; then
echo "Please enter machine name"
return 1
fiif [ -z "${instance}" ]; thenif [[ -z $instance ]]; thenip=$(echo $instance | awk '{print $2}')
pem=$(echo $instance | awk '{print $1}')read pem ip junk <<< $instanceContext
StackExchange Code Review Q#41782, answer score: 6
Revisions (0)
No revisions yet.