从 ~/.ssh/config 打印别名——带或不带尾随连字符

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

我有以下文件,它是 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

我需要打印以 vps* 开头的别名,下面(复制的)片段将完全做到这一点。

$ 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

现在我想打印所有没有 -old 后缀的别名,添加 | grep -v old 有效。

$ 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

有没有更干净的方法?最好只涉及 1 个工具,我尝试使用 awk 命令无济于事。

您可以使用 sed,如果您使用支持比 grep 更扩展的正则表达式的 -n(无打印),它具有类似 grep 的模式。可以在此处找到过滤掉以 -old 结尾的行的技巧:Sed regex and substring negation:

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

反向(包括-old)稍微简单一些,因为它只需要正匹配:

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

您可以向 awk 命令添加 $i!~/-old$/ 条件:

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

(注意:当它不在双引号中时,我更喜欢 ~ 而不是 $HOME,以防路径中出现奇怪的字符。)

grep -Po '(?<=Host )vps\d+(?!-old)' file | sort -uV

这可能适合您 (GNU sed):

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

使用 -n-E 选项关闭隐式打印和扩展正则表达式。

如果一行不包含 -old,则匹配以 Host 开头的行,后跟一些空格,然后是 vps,然后是零个或多个非空格,然后是任何东西并将其替换为 vps 后跟任何非空白并打印结果。

要仅显示其中包含 -old 的行,请使用:

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

N.B。这依赖于 Host 行不包含注释或多个主机名。

当你想要的字符串总是在以 Host:

开头的行的第二个字段中时,你为什么要循环?
$ awk '/^Host vps/ && !/-old/{ print  }' file
vps2
vps3
vps4
vps5
vps6
vps7
vps8
vps13

我在评论中看到您实际上希望输出全部在 1 行上,即:

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