5

I'm writing a shell script where I need to obtain an IdentityFile from an ssh config file. The ssh config file looks like this:

​Host AAAA
    User aaaa
    IdentityFile /home/aaaa/.ssh/aaaaFILE
    IdentitiesOnly yes
    PubkeyAuthentication=yes
    PreferredAuthentications=publickey
​Host BBBB
    User bbbb
    IdentityFile /home/aaaa/.ssh/bbbbFILE
    IdentitiesOnly yes
    PubkeyAuthentication=yes
    PreferredAuthentications=publickey
​Host CCCC
    User cccc
    IdentityFile /home/aaaa/.ssh/ccccFILE
    IdentitiesOnly yes
    PubkeyAuthentication=yes
    PreferredAuthentications=publickey

I want to obtain the string following IdentityFile based on a given Hostname and put it in a variable. The hostname will be provided by a shell variable called ${HOSTNAME}.

I was able to use the answer at Bash extract user for a particular host from ssh config file to read the config file and grep for a single specific IdentityFile based on a single specific Hostname, but I can't get the hang of passing a variable into awk.

So far I've tried

SSH_CONFIG="/home/aaaa/.ssh/config"
# Note AAAA is the hostname for this case
KEY=$(awk '/^Host AAAA$/{x=1}x&&/IdentityFile/{print $2;exit}' ${SSH_CONFIG})
echo "${KEY}" 

OUTPUT: "/home/aaaa/.ssh/aaaaFILE"

which works because I'm giving the exact hostname to parse. But using

SSH_CONFIG="/home/aaaa/.ssh/config"
HOSTNAME=AAAA
KEY=$(awk -vcon="${HOSTNAME}" '/^Host con$/{x=1}x&&/IdentityFile/{print $2;exit}' ${SSH_CONFIG})
echo "${KEY}" 

OUTPUT: ""

does not work. I know for a fact ${HOSTNAME} is being set because I am setting myself (and echoing it). I would like to pass a variable because I do not want the hostname hardcoded and will not know what the value is until the script is called.

I am also stuck using and older version of ssh (OpenSSH_6.6.1) which does not have the convenient ssh -G HOSTNAME option.

What am I missing when it comes to awk variables? Is there a better way to do this?

Wimateeka
  • 2,474
  • 2
  • 16
  • 32

3 Answers3

5

I appreciate the scripting attempts, but OpenSSH client already knows how to parse the configuration:

ssh -G $hosname | grep identityfile | awk '{print $2}' | head -n 1

note, that it will also list the default identities, but with IdentitiesOnly=yes it should list the one from configuration as the first one.

Jakuje
  • 24,773
  • 12
  • 69
  • 75
  • As I mentioned above, I am also stuck using and older version of ssh (OpenSSH_6.6.1) which does not have the convenient ssh -G HOSTNAME option. Unless you would like to roll a Debian package for me, I am stuck scripting sans `ssh -G`. – Wimateeka Aug 15 '17 at 11:46
  • 1
    @Wimateeka sorry, I missed that part. Maybe time to update? – Jakuje Aug 15 '17 at 11:48
  • That's unfortunately not my decision to make, but trust me, I'd love to update. I've already been dinged with not having a verbose option for sshpass because of this too. – Wimateeka Aug 15 '17 at 11:54
2

With GNU grep and Perl Compatible Regular Expressions:

hostname="AAAA"
grep -Poz "Host $hostname(.*\n)*?.*IdentityFile \K.*" ~aaaa/.ssh/config

Output:

/home/aaaa/.ssh/aaaaFILE
Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • Thanks for this suggestion @Cyrus. This worked for me. I'm choosing your answer because `grep` allows for more brevity. – Wimateeka Aug 15 '17 at 14:12
1

mmm for some reason, the example you posted has strange non-printable characters before Host word. This regular expression only matched the first line: /^Host/, while it should match 3 total lines.

I fixed that by deleting those characters and saving it again.

So, answering your question, you can't use variables inside a regular expression in awk.

But this also works and do the same:

HOSTNAME="BBBB"
awk -v host=$HOSTNAME '/Host/ && $2==host {found=1} /IdentityFile/ && found {print $2; exit}' ${SSH_CONFIG}
valrog
  • 216
  • 1
  • 6