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

Viewed 107

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 Answers

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

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.)

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.

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
grep -Po '(?<=Host )vps\d+(?!-old)' file | sort -uV
Related