ファイルに 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正規表現で区切られた「スニペット」で行が見つかった場合は、その行を印刷し、fileそうでなければ何も印刷しません。

したがって、返された文字列が存在することを確認してください。

sed 何も印刷されないときもゼロで終了するため、終了状態を確認しません。

いくつかの追加の注意:

  • シェルの二重引用符の中にあるので、\\1を表現する必要があります。\
  • $V_MAQUINAシェル変数を使用するには、二重引用符を使用します。$V_NAGIOS_COMMAND
  • %前の正規表現で正規表現の区切り文字として選択したが、変数には表示されない文字を自由に選択できます。$V_NAGIOS_COMMAND

答え2

まったく:

/^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

関連情報