当文件中存在 string1 时查找 string2

当文件中存在 string1 时查找 string2

我有一个配置文件(来自 Nagios),其结构如下:

define service{
    use                     pruebaspre-service,srv-pnp
    host_name               server1.es
    servicegroups           pruebasdatasourcesoaspre-servicegroup,pruebaspre-servicegroup
    service_description     Estado DataSource - cfio  JUVEPoolDSPoolDS
    check_command           check_ds_oas!cfio!JUVEPoolDSPoolDS!/opt/oracle/ias10g/10.1.2!1!0
}


define service{
    use                     pruebaspre-service,srv-pnp
    host_name               server1.es
    servicegroups           pruebasdatasourcesoaspre-servicegroup,pruebaspre-servicegroup
    service_description     Estado DataSource - cfio  REMEPoolDS
    check_command           check_ds_oas!cfio!REMEPoolDS!/opt/oracle/ias10g/10.1.2!1!0
}


define service{
    use                     pruebaspre-service,srv-pnp
    host_name               server2.es
    servicegroups           pruebasdatasourcesoaspre-servicegroup,pruebaspre-servicegroup
    service_description     Estado DataSource - cfio  iris_usr_irisPoolDS
    check_command           check_ds_oas!cfio!iris_usr_irisPoolDS!/opt/oracle/ias10g/10.1.3!1!0
}


define service{
    use                     pruebaspre-service,srv-pnp
    host_name               server2.es
    servicegroups           pruebasdatasourcesoaspre-servicegroup,pruebaspre-servicegroup
    service_description     Estado DataSource - cfio  REMEPoolDS
    check_command           check_ds_oas!cfio!REMEPoolDS!/opt/oracle/ias10g/10.1.2!1!0
}

define service{
    use                     pruebaspre-service,srv-pnp
    host_name               server2.es
    servicegroups           pruebasdatasourcesoaspre-servicegroup,pruebaspre-servicegroup
    service_description     Estado DataSource - cfio  redt2_usr_redt2PoolDS
    check_command           check_ds_oas!cfio!redt2_usr_redt2PoolDS!/opt/oracle/ias10g/10.1.3!1!0
}

要在此文件中注册新服务,我需要首先查找该服务是否存在,为此我必须找到该check_command服务host_name未注册。

例如我要注册:

define service {
     use pre-service tests, srv-pnp
     host_name server1.es
     servicegroups testsdatasourcesoaspre-servicegroup, pre-servicegroup tests
     service_description DataSource Status - cfio REMEPoolDS
     check_command check_ds_oas! cfio! REMEPoolDS! /opt/oracle/ias10g/10.1.2! 1! 0
}

所以在文件中我应该寻找它不存在。

我用 while 循环尝试了读取文件并在找到时

check_command check_ds_oas! Cfio! REMEPoolDS! /Opt/oracle/ias10g/10.1.2! 1! 0

它看起来不会是下一个

host_name server1.es
V_NAGIOS_COMMAND=check_ds_oas!cfio!REMEPoolDS!/opt/oracle/ias10g/10.1.2!1!0
if [ `grep ${V_NAGIOS_COMMAND} --count $V_FILE_NAGIOS` -ge 1 ] ; then
    while read LINEA_CONFIG
    do
        V_DIRECTIVA=`echo $LINEA_CONFIG| awk '{print $1} '`
        V_VALOR_DIRECTIVA=`echo $LINEA_CONFIG| awk '{print $2} '`
        if [ $V_DIRECTIVA = check_command ]&&[ $V_VALOR_DIRECTIVA = $V_NAGIOS_COMMAND ]; then
            V_COMANDO_ENCONTRADO=1
        elif [ $V_DIRECTIVA = host_name ]&& [ $V_COMANDO_ENCONTRADO = 1 ] ; then
            if [ $V_VALOR_DIRECTIVA = $V_MAQUINA ] ; then
                ((V_EXISTEN_DATOS++))
                return 1
            else
                V_COMANDO_ENCONTRADO=0
            fi
        fi
    done < <(tac $V_FILE_NAGIOS| grep -vE "^#|^$")
fi

但它很慢。

答案1

如果我很好地理解了您的要求,那么这看起来是一项sed可以做得很好的工作,因为它能够在输入流中分隔“子流”。

这应该是 POSIX:

sed -n "/^define service/,/^}/{/^[[:blank:]]\\{1,\}host_name[[:blank:]]\\{1,\\}${V_MAQUINA}/,/^}/{\\%^[[:blank:]]\\{1,\\}check_command[[:blank:]]\\{1,\\}${V_NAGIOS_COMMAND}%{p;q}}}" file

或者,如果您可以使用 GNU sed,可以减少字符串中的转义:

sed -En "/^define service/,/^\\}/{/^[[:blank:]]+host_name[[:blank:]]+${V_MAQUINA}/,/^\\}/{\\%^[[:blank:]]+check_command[[:blank:]]+${V_NAGIOS_COMMAND}%{p;q}}}" file

解释:

sed -En  # use Extended Regular Expressions, and don't print by default

# main `sed` script for entire stream
/^define service/,/^\\}/  # between 'define service' and '}'
{  # sub-stream: between specified 'host_name' and '}'
/^[[:blank:]]+host_name[[:blank:]]+${V_MAQUINA}/,/^\\}/
{  # look for specified 'check_command', using '%' because '/' can be in command
\\%^[[:blank:]]+check_command[[:blank:]]+${V_NAGIOS_COMMAND}%
{p;q}  # if found, print line and quit `sed`
}
}

check_command如果在由正则表达式分隔的“snippet”中找到该行,则打印该行file,如果未找到,则不打印任何内容。

因此,您只需检查返回的字符串是否存在。

不检查退出状态,因为sed 当没有打印任何内容时也会退出 0。

一些附加说明:

  • 我们需要\\表达 1\因为我们在 shell 的双引号内
  • 我们使用双引号来使用 shell 的$V_MAQUINA变量$V_NAGIOS_COMMAND
  • 我在上一个正则表达式中选择了作为正则表达式分隔符,但是您可以自由选择变量%中不会出现的任何字符$V_NAGIOS_COMMAND

答案2

在 awk 中:

/^define service/{

    found_command=0
    found_host=0

    while (getline && $0 !~ "^}") {

        # test host
        if($1 == "host_name") {
            if ($2 == new_host) {
                found_host=1
            }else{
                next
            }
        }

        # test check_command
        if($1 == "check_command"){
            cmd = gensub(/^\s*check_command\s*/, "", 1)
            if (cmd == new_command) {
                found_command=1
            }else{
                next
            }
        }
    }

    if (found_command && found_host)
        exit 1
}

可以这样使用:

new_host='...'
new_command='...'
if awk -v new_host="$new_host" -v new_command="$new_command" -f script.awk cfg_file ; then
    echo "you can register it now"
fi

相关内容