Substituir caractere particular, mas não se estiver dentro ()

1

Estou procurando um comando de uma linha para tornar um arquivo mais legível. Desejo substituir todos os caracteres ; por newline , a menos que esteja dentro de um conjunto de () . Isso está em um firewall, então eu só posso usar o bash; não perl etc.

Exemplo de entrada:

ProductName: Threat Emulation; product_family: Threat; Destination: (countryname: United States; IP: 127.0.0.1; repetitions: 1) ; FileName: (file_name: myfile) ;

Resultado esperado:

ProductName: Threat Emulation
product_family: Threat
Destination: (countryname: United States; IP: 127.0.0.1; repetitions: 1)
FileName: (file_name: myfile)
    
por Jonathan 14.07.2016 / 16:42

2 respostas

4

Um pouco de regex confuso para sed, mas viável

sed '
    :a                                                 #mark return point
    s/\(\(^\|)\)[^(]\+\);\s*\([^)]\+\((\|$\)\)/\n/ #remove ; between ) and (
    ta                                                 #repeat if substitute success
    s/[[:blank:];]\+$//                                #remove ; with spaces at end
    '

Explicação de regex de Breif:

  • ^\|) do início da linha ou )
  • [^(]\+ de quaisquer símbolos, mas (
  • ;\s* ponto-e-vírgula com espaço (s) possível (s)
  • (\|$ até o final da linha ou (
por 14.07.2016 / 17:27
0

Se você tiver awk, você pode usar os parênteses como separadores de campo:

awk -F '[()]' '{
    for (i=1; i<=NF; i+=2) {
        if ($i) {
            gsub(/; */,"\n",$i)
            printf "%s", $i
            if ($(i+1)) printf "(%s)", $(i+1)
        }
    }
    print ""
}' <<END
ProductName: Threat Emulation; product_family: Threat; Destination: (countryname: United States; IP: 127.0.0.1; repetitions: 1) ; FileName: (file_name: myfile) ;
END
ProductName: Threat Emulation
product_family: Threat
Destination: (countryname: United States; IP: 127.0.0.1; repetitions: 1) 
FileName: (file_name: myfile) 

O ponto e vírgula à direita fornece uma nova linha à direita.

    
por 15.07.2016 / 04:24