1

我有以下文件,它是 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 命令无济于事。

4

5 回答 5

5

您可以使用sed,如果您使用-n(无打印)支持比grep. -old在这里可以找到过滤掉以结尾的行的技巧: Sed regex and substring negation

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

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

sed -n "s/^Host\s\+\(vps\S*-old\)\s*\(#.*\)\?/\1/p" $HOME/.ssh/config
于 2022-01-10T04:47:22.243 回答
2

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

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

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

于 2022-01-10T04:48:42.433 回答
1

这可能对您有用(GNU sed):

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

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

如果一行不包含-old,则匹配一行开头Host,后跟一些空格,然后是vps,后跟零个或多个非空格,然后是任何内容,vps然后用任何非空格替换它并打印结果。

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

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

注意 这依赖于Host不包含注释或多个主机名的行。

于 2022-01-10T12:37:05.493 回答
1

当你想要的字符串总是在以 开头的行的第二个字段中时,我知道你为什么要循环Host

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

我在评论中看到你实际上希望输出全部在 1 行,那就是:

$ awk '/^Host vps/ && !/-old/{ printf "%s%s", sep, $2; sep=OFS } END{print ""}' file
vps2 vps3 vps4 vps5 vps6 vps7 vps8 vps13
于 2022-01-10T14:20:56.537 回答
0
grep -Po '(?<=Host )vps\d+(?!-old)' file | sort -uV
于 2022-01-10T05:02:38.470 回答