【问题标题】:Printing alias from ~/.ssh/config— with or without trailing hyphen从 ~/.ssh/config 打印别名——带或不带尾随连字符
【发布时间】:2022-01-10 22:27:46
【问题描述】:

我有以下文件,它是 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* 开头的别名,下面(复制的)sn-ps 将完全做到这一点。

$ 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命令无济于事。

【问题讨论】:

    标签: bash awk sed grep ssh-config


    【解决方案1】:

    您可以使用sed,如果您使用支持比grep 更扩展的正则表达式的-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
    

    【讨论】:

    • 如果我只想打印具有-old 后缀的别名怎么办?
    • 然后你删除第一个命令/-old/b;并将-old添加到第一个捕获组的末尾,就像vps在开头一样。
    • @Liso。我在更新中说明了
    • 您应该提到\s\+ 需要GNU sed(也许还有\?,我不确定那个)。由于它无论如何都需要 GNU sed,因此您可以通过添加 -E 来启用 ERE 然后删除许多反斜杠来使其更简洁。顺便说一句,一个好的经验法则是始终在 shell 字符串(包括脚本)周围使用单引号,并且仅在您有特定的 shell 需要对字符串/脚本进行解释时才使用双引号或不使用引号。
    • @EdMorton。很好的报价。当我从另一个帖子中复制和粘贴时会发生这种情况:) 我稍后会研究其余部分并修复它
    【解决方案2】:

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

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

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

    【讨论】:

    • 谢谢,我可以将它与ORS 结合起来得到一行结果。
    • 如果输入文件包含User vpsmith,例如它将vpsmith作为主机名输出,则会失败。
    【解决方案3】:

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

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

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

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

    要只显示带有-old 的行,请使用:

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

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

    【讨论】:

      【解决方案4】:

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

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

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

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

      【讨论】:

        【解决方案5】:
        grep -Po '(?<=Host )vps\d+(?!-old)' file | sort -uV
        

        【讨论】:

        • 如果你要建议-P,你需要一些注意事项
        • @MadPhysicist 究竟有什么警告?
        • GNU grep,不确定最低版本。
        • 这很明显。
        猜你喜欢
        • 2018-03-06
        • 2019-02-02
        • 2022-06-16
        • 2014-05-26
        • 1970-01-01
        • 1970-01-01
        • 2010-09-08
        相关资源
        最近更新 更多