Bash extract user for a particular host from ssh config file - bash

I'm writing a bash script where I need to obtain a particular user from an ssh config file. The ssh config file looks a little something like this:
HOST blag
HostName blag.net.au
Port 2683
User blaguser
Host bloo
User ABCDEF
IdentityFile ~/.ssh/id_rsa
HOST biff
HostName biff.net.au
Port 2683
User biffuser
I want to obtain the string 'ABCDEF' and put it in a variable, by searching for Host bloo.
I was able to use the answer at https://superuser.com/questions/791374/get-variable-values-from-config-file/791387#791387?newreg=6626dd5535194d0180a91b6ace31e16f to read the config file but it assigns the array with the last host entry in the file.
I'm able to delete the host entry with this answer How can I remove a Host entry from an ssh config file?. The sed command here could be edited to extract the correct User but I'm not sure precisely how
I'm having a lot of trouble with it. Can anyone assist? An answer which uses sed would be preferable.

You can use ssh configuration test mode to parse the configuration file and return you the expected value:
ssh -G hostname | grep "^user "
This should work since openssh-6.8.

Adding to #Jakuje's correct answer. This one will return only the username
$ ssh -G hostname | grep -m1 -oP "(?<=user ).*"
ubuntu
where grep parameters mean
-m1 - stop reading after first matches
-o - print only the matching part of the line
-P - use Perl compatible positive look behind regex

As per 123's comment above:
var=$(awk '/^Host bloo$/{x=1}x&&/User/{print $2;exit}' ssh.conf)
That will assign value ABCDEF to var.

Related

Make a parameter subsitution in bash aliases for ssh

Is there a way I can create a alias for this command and have it ask for the host.
ssh -i .ssh/name.pem root#
Thx
Something like the following should work (not tested)
sshfunction(){
echo "Specify your hostname:"
read host
ssh -i .ssh/name.pem root#"$host"
}
Then:
$ sshfunction
Though if it was me, I'd just provide the hostname as a variable and cut-out the middle man.
Better yet, populate your ~/.ssh/config file (if it doesn't exist you can just create it):
host MyHostName
Hostname 123.456.7.89
User username
Then:
$ ssh MyHostName

Concatenating a local file with a remote one

These three lines of code require authentication twice. I don't yet have password-less authentication set up on this server. In fact, these lines of code are to copy my public key to the server and concatenate it with the existing file.
How can I re-write this process with a single ssh command that requires authentication only once?
scp ~/local.txt user#server.com:~/remote.txt
ssh -l user user#server.com
cat ~/remote.txt >> ~/otherRemote.txt
I've looked into the following possibilities:
command sed
operator ||
operator &&
shared session: Can I use an existing SSH connection and execute SCP over that tunnel without re-authenticating?
I also considered placing local.txt at an openly accessible location, for example, with a public dropbox link. Then if cat could accept this as an input, the scp line wouldn't be necessary. But this would also require an additional step and wouldn't work in cases where local.txt cannot be made public.
Other references:
Using a variable's value as password for scp, ssh etc. instead of prompting for user input every time
https://superuser.com/questions/400714/how-to-remotely-write-to-a-file-using-ssh
You can redirect the content to the remote, and then use commands on the remote to do something with it. Like this:
ssh user#server.com 'cat >> otherRemote.txt' < ~/local.txt
The remote cat command will receive as its input the content of ~/local.txt, passed to the ssh command by input redirection.
Btw, as #Barmar pointed out, specifying the username with both -l user and user# was also redundant in your example.

How to autocomplete or use abbreviations in bash command

Everyday I have to transfer files to many (6) AWS EC2 instances via SCP, from my bash terminal, on Linux Debian 8. I have to hand write:
i) files to transfer;
ii) destination folder;
iii) url to my .pem certificate;
iv) openning urls on the servers: ec2-user#XX.XX.XXX....
As a lazy programmer I want to use some kind of abbreviation in order to type less, having in mind that iii) and iv) are the same generally.
First I wrote a bash script which asks me for files to be transferred and folder on my server, however it takes more time due to the fact that prompts for an answer every time I transfer. Instead, I can just use arrow to repeat the bash command previously introduced.
Here is an example of the current command I use to run:
scp -i /pem/aws.pem file_to_upload.txt ec2-user#XX-XX-XX-XX.amazonwas.com:/var/www/html/folder/
the following strings require repeated typing:
scp -i /pem/aws.pem
ec2-user#..... // this is a large string of 64 characters.
I'd love some sort of placeholder, where I just type the path to files to upload and the remote folder.
How can I autocomplete or use abbreviations, like VIM to insert the same recurrent text in a bash command?
All the solutions already posted work, but they are really ugly and not the way how it should be. Remember, we still have ~/.ssh/config?
scp -i /pem/aws.pem file_to_upload.txt ec2-user#XX-XX-XX-XX.amazonwas.com:/var/www/html/folder/
will boil down to
scp file_to_upload.txt am:/var/www/html/folder/
if you set up your ~/.ssh/config:
Host am:
Hostname XX-XX-XX-XX.amazonwas.com
User ec2-user
IdentityFile /pem/aws.pem
There your local file gets auto-completed and remote directory also if you don't use passphrase (or set up ControlMaster and ControlPersist options - this will even be fast!).
Sounds like you could take advantage of using some bash aliases in your bashrc or bash_profile.
Take a look at my .bashrc file on githut
I often need to know what is my ip address. One example of a bash alias is my showip alias.
alias showip='ifconfig | grep "inet" | grep -v 127.0.0.1'
I have also created aliases to ssh into my Linux boxes. You could create a bash alias that should solve your problem.
Copying directory recursively from host:
scp -r user#host:/directory/SourceFolder TargetFolder
NOTE: If the host is using a port other than port 22, you can specify it with the -P option:
scp -P 2222 user#host:/directory/SourceFile TargetFile
When you are connecting to your bash terminal with a ssh program, see what keyboard mappings your ssh supports.
Other options, based on
echo "This is a line I do not want to type twice"
Look how you can use the bash history
!!
^twice^two times^
You can put your abbreviations in shell variables
no2="This is a line I do not want to type twice"
echo "${no2}"
And you can use an alias
my2='echo "This is a line I do not want to type twice"'
my2
The shell variables and aliases can be put in ${HOME}/.bashrc.

Can an ~/.ssh/config file use variables?

I am writing an SSH config file and want to perform a bit of logic. For example:
Host myhost1
ProxyCommand ssh -A {choose randomly between [bastion_host1] and [bastion_host2]} -W %h:%p
Is it possible to achieve the above using (bash?) variables? Thanks!
Your ProxyCommand can be a shell script.
host myhost1
ProxyCommand $HOME/bin/selecthost %h %p
And then in ~/bin/selecthost:
#!/usr/bin/env bash
hosts=(bastion1 bastion2)
onehost=${hosts[$RANDOM % ${#hosts[#]}]}
ssh -x -a -q ${2:+-W $1:$2} $onehost
Untested. Your mileage may vary. May contain nuts.
Per comments, I've also tested the following, and it works nicely:
host myhost1 myhost2
ProxyCommand bash -c 'hosts=(bastion1 bastion2); ssh -xaqW%h:22 ${hosts[$RANDOM % ${#hosts[#]}]}'
Of course, this method doesn't allow you to specify a custom port per host. You could add that to the logic of a separate shell script if your SSH config matches multiple hosts in the same host entry.
In ~/.ssh/config you cannot have much logic, and no Bash. The manual for this file is in man ssh_config, and it makes no mention of such feature.
What you can do is create a script that will have the logic you need, and make you ssh configuration call that script.
Something along the lines of:
ProxyCommand sudo /root/bin/ssh-randomly.sh [bastion_host1] [bastion_host2]
And write a Bash script /root/bin/ssh-randomly.sh to take two hostname parameters, select one of them randomly, and run the real ssh command with the appropriate parameters.
No; .ssh/config is not processed by any outside program. You'll need a shell function along the lines of
ssh () {
(( $RANDOM % 2 )) && bastion=bastion_host1 || bastion=bastion_host2
command ssh -A "$bastion" "$#"
}
This can be handled within ssh config by using a helper app. For example,
Host myhost match exec "randprog"
hostname host1
Host myhost
hostname host2
and then randprog will randomly return 1 or 0 (0 will match the first line, giving host1).

Bash script to ssh to specific urls of a common format?

All the vms at work I need to ssh into are of a common format (stuff014.stuff.com) with differing numbers. Is there a quick way to connect to them without making a big ssh config file and without using alias?
(Replace <your_user_name> with your user name.)
#!/bin/bash
ssh <your_user_name>#stuff$1.stuff.com
The $1 is the first parameter given, so if this was named easyssh.sh and you needed to get to 014 do
./easyssh.sh 014
To make this even better add it to a folder on your PATH (or add the directory to your path, whichever suits your needs).
You wouldn't need a big config file. A minimal implementation only requires two lines.
host stuff*
HostName %h.stuff.com
Any host you try to connect to is matched against the host patterns in your config file, stopping at the first one that matches. The HostName directive uses the matched host (%h) to construct the actual host name to connect to.
Then you can abbreviate the host name when running ssh:
$ ssh stuff014
# Connects to stuff014.stuff.com

Resources