代码之家  ›  专栏  ›  技术社区  ›  jackcsprat

从逗号分隔的文件中删除主机

  •  0
  • jackcsprat  · 技术社区  · 4 年前

    主机组文件的格式为:

    server1,server2,server3,server4
    

    server1,server3,server4
    

    sed -i 's/\bserver2\b,//g' myfile
    

    我想做的是将主机名列表输入一个小脚本,以删除一堆主机(以及它们后面的逗号),其内容类似于下面的内容。问题在于,放置一个像$x这样的变量会破坏脚本,因此不会发生任何事情。

    #!/bin/ksh
    for x in `cat /tmp/list`
    do
    sed -i 's/\b${x}\b,//g' myfile
    done
    

    我想我已经很接近一个解决方案了,但是需要一点帮助。非常感谢您的帮助。

    0 回复  |  直到 4 年前
        1
  •  2
  •   Ian McGowan    4 年前

    使用单引号告诉shell不要替换${x}-如果您想搜索变量插值,它会关闭变量插值。 https://www.tldp.org/LDP/abs/html/quotingvar.html . 因此,请在sed替换字符串前后使用双引号:

    while read -r x; do sed -i "s/\b${x},\b//g" myfile; done < /tmp/list
    

    但由于最后一个字段后面没有逗号,所以最好运行两个sed命令,一个查找\bword,\b,另一个查找word$-其中\b是单词边界,$是行尾。

    while read -r x; do sed -i "s/\b${x},\b//g" myfile; sed -i "s/,${x}$//" myfile ; done < /tmp/list
    

    另一个可能的边界条件是,如果一行上只有server2,而这正是您要删除的内容呢?可能会添加第三个sed,但此sed后面会留下一个空白行,您可能需要删除:

    while read -r x
    do
      sed -i "s/\b${x},\b//g" myfile  # find and delete word,
      sed -i "s/,${x}$//" myfile      # find and delete ,word
      sed -i "s/^${x}$//" myfile      # find word on a line by itself
    done < t
    
        2
  •  2
  •   compuphys    4 年前

    这非常好用:

    #!/bin/bash
    IN_FILE=$1
    shift; sed -i "s/\bserver[$@],*\b//g" $IN_FILE; sed -i "s/,$//g" $IN_FILE
    

    如果你像 ./remove_server.sh myfile "1 4" 对于包含 server1,server2,server3,server4 ,可以得到以下输出:

    server2,server3
    

    快速解释它的作用:

    • shift "myfile" 未输入正则表达式)
    • 弗斯特 sed 删除在字符串中作为参数提供的数字的服务器(例如“14”)
    • 塞德
    • 这个 \b 匹配单词边界

    https://regex101.com/r/FxmjO5/1

    此脚本在更一般意义上的工作示例:

    # This is some file containing server info:
    # Here are some servers:
    server2,server3
    
    # And here are more servers:
    server7,server9
    

    具有 ./remove_server.sh myfile "2 9" 得到了这个:

    # This is some file containing info:
    # Here are some servers:
    server3
    
    # And here are more servers:
    server7
    
        3
  •  1
  •   Jetchisel    4 年前

    很确定有一个纯粹的 sed 解决方案,但这里有一个脚本。

    #!/usr/bin/env bash
    
    hosts=()
    
    while read -r host; do
      hosts+=("s/\b$host,\{,1\}\b//g")
    done < /tmp/list
    
    opt=$(IFS=';' ; printf '%s' "${hosts[*]};s/,$//")
    
    sed "$opt" myfile
    
    • 塞德 但只能一行一行 调用。以防万一,假设你必须移除20+模式 不会运行20+次。

    • 添加 -i 如果你认为输出正常。

        4
  •  0
  •   James Brown    4 年前

    $ remove="(server1|server4)"
    $ perl -p -e  "s/(^|,)$remove(?=(,|$))//g;s/^,//" file
    server2,server3
    

    解释:

    • remove="(server1|server4)" "server1" "server."
    • "s/(^|,)$remove(?=(,|$))//g" 双引号以允许shell变量,删除前导逗号,后面应跟逗号或字符串结尾
    • s/^,// file 删除第一个条目时删除前导逗号

    -i 切换到内嵌编辑。

        5
  •  0
  •   Shawn    4 年前

    bash 读取要从标准输入中删除的服务器的脚本,每行一个,并使用 perl 要从主机文件中删除它们(作为脚本的第一个参数传递):

    #!/usr/bin/env bash
    # Usage: removehost.sh hostgroupfile < listfile
    
    mapfile -t -u 0 servers
    IFS="|"
    export removals="${servers[*]}"
    perl -pi -e 's/,?(?:$ENV{removals})\b//g; s/^,//' "$1"
    

    server2 不会移除 server22 .