Printing alias from ~/.ssh/config— with or without trailing hyphen

141 Views Asked by At

I have following file, it's a config file for ssh.

Host vps2 # Linode
    HostName xxx.xx.xx.xxx
    User foo_user

Host vps3 # Vultr
    HostName xxx.xx.xx.xxx
    User foo_user   

Host vps4
    HostName xxx.xx.xx.xxx
    User foo_user

Host vps5
    HostName xxx.xx.xx.xxx
    User foo_user 

Host vps6
    HostName xxx.xx.xx.xxx
    User foo_user 

Host vps7 # DigitalOcean
    HostName xxx.xx.xx.xxx
    User foo_user

Host vps8 # GCP
    HostName xxx.xx.xx.xxx
    User foo_user   

Host pi
   HostName xxx.xx.xx.xxx
   User pi

# OLD SHALL NOT BE USED

Host vps13
    HostName xxx.xx.xx.xxx
    User foo_user

Host vps14-old
   HostName xxx.xx.xx.xxx
   User foo_user 

Host vps4-old
    HostName xxx.xx.xx.xxx
    User foo_user 

Host vps15-old
   HostName xxx.xx.xx.xxx
   User foo_user 

Host vps11-old
    HostName xxx.xx.xx.xxx
    User foo_user

I need to print alias that start with vps*, below (copied) snippets will exactly do that.

$ awk '{for(i=1;i<=NF;i++){if($i~/^vps/){print $i}}}' $HOME/.ssh/config
vps2
vps3
vps4
vps5
vps6
vps7
vps8
vps3-old
vps4-old
vps5-old
vps11-old

Now I want to print all alias that has no -old suffix, adding | grep -v old works.

$ awk '{for(i=1;i<=NF;i++){if($i~/^vps/){print $i}}}' $HOME/.ssh/config | grep -v "old"
vps2
vps3
vps4
vps5
vps6
vps7
vps8

Is there any cleaner way ? Preferably involving only 1 tools, I tried playing with awk command to no avail.

5

There are 5 best solutions below

2
Gordon Davisson On BEST ANSWER

You could add a $i!~/-old$/ condition to the awk command:

awk '{for(i=1;i<=NF;i++){if($i~/^vps/ && $i!~/-old$/){print $i}}}' ~/.ssh/config

(Note: I prefer ~ over $HOME when it's not in double-quotes, just in case of weird characters in the path.)

7
Mad Physicist On

You can use sed, which has a grep-like mode if you use -n (no print) that supports a more extended regex than grep. The trick for filtering out lines ending in -old is found here: Sed regex and substring negation:

sed -n "/-old/b; s/^Host\s\+\(vps\S*\)\s*\(#.*\)\?/\1/p" $HOME/.ssh/config

The inverse (including -old) is a bit simpler, since it only requires positive matches:

sed -n "s/^Host\s\+\(vps\S*-old\)\s*\(#.*\)\?/\1/p" $HOME/.ssh/config
4
konsolebox On
grep -Po '(?<=Host )vps\d+(?!-old)' file | sort -uV
0
potong On

This might work for you (GNU sed):

sed -En '/-old/!s/^Host\s*(vps\S*).*/\1/p' file

Turn off implicit printing and on extended regexps by using the -n and -E options.

If a line does not contain -old, match on a line beginning Host followed by some whitespace, followed by vps, followed by zero or more non-whitespace, followed by anything and replace it by vps followed by any non-whitespace and print the result.

To only show lines with -old in them, use:

sed -En '/-old/s/^Host\s*(vps\S*).*/\1/p' file

N.B. This relies on Host lines not containing comments or more than one host name.

0
Ed Morton On

Idk why you're looping when the string you want is always in the 2nd field of a line that starts with Host:

$ awk '/^Host vps/ && !/-old/{ print $2 }' file
vps2
vps3
vps4
vps5
vps6
vps7
vps8
vps13

I see in comments you actually want the output all on 1 line, that'd be:

$ awk '/^Host vps/ && !/-old/{ printf "%s%s", sep, $2; sep=OFS } END{print ""}' file
vps2 vps3 vps4 vps5 vps6 vps7 vps8 vps13