Extraindo valores de um arquivo digitado por várias chaves

2

Considere um arquivo com key=value pares e cada key é opcionalmente uma concatenação de vários key s. Em outras palavras, muitos key s podem mapear para um value . A razão por trás disso é que cada key é uma palavra relativamente curta em comparação com o comprimento do value , portanto, os dados estão sendo 'compactados' em linhas menores.

Ilustração (ou seja, não os valores reais):

$ cat testfile
AA,BB,CC=a-lengthy-value
A,B,C=a-very-long-value
D,E,F=another-very-long-value
K1,K2,K3=many-many-more
Z=more-long-value

É válido assumir que todos os key s são exclusivos e não conterão os seguintes caracteres:

  • key delimiter: ,
  • delimitador de valor-chave: =
  • caractere de espaço em branco:

key s pode vir de qualquer forma no futuro (com as restrições acima), mas se ajudar, eles atualmente aderem ao seguinte regex coincidentemente: %código%. Da mesma forma, [[:upper:]]{2}[[:upper:]0-9] s não conterá value , portanto, = pode ser usado com segurança para dividir cada linha. Não existem multi-linhas = s ou key s, portanto, também é seguro processar linha por linha.

Para facilitar a extração de dados desse arquivo, uma função value é definida como:

getval() {
    sed -n "/^\([^,]*,\)*$1\(,[^=]*\)*=\(.*\)$/{s///p;q}" testfile
}

Assim, chamar getval() retornará o valor getval A , não a-very-long-value . Ele também não deve retornar nada para um a-lengthy-value inexistente.

Perguntas:

  • A definição atual de key é robusta o suficiente?
  • Existem formas alternativas de executar a extração de dados que são possivelmente mais curtas / mais expressivas / mais restritivas?

Por que vale a pena, esse script será executado com getval() e bash do cygwin que vem com ele. A portabilidade não é necessária aqui como resultado (isto é, apenas pontos de brownie serão dados). Obrigado!

edit:

Função corrigida, esclarecimento adicional sobre as chaves.

edit 2:

Acrescentou esclarecimentos sobre o formato (sem multi-linhas) e portabilidade (não é um requisito).

    
por h.j.k. 12.01.2015 / 11:24

2 respostas

2

Você pode escrever de forma muito mais legível usando awk :

getval() {
    awk -F'=' '$1~/\<'"$1"'\>/{print $2}' testfile
}
    
por 12.01.2015 / 11:53
1

com sed ...

getval() { sed "/^\([^=]*,\)*$1[,=]/!d;s/.*=//;q"; } <infile

Você pode querer validar $1 como entrada.

Ou com o GNU grep e cut :

getval() { grep -Em1 "^([^=]*,)*$1[,=]" | cut -d= -f2-; } <infile
    
por 12.01.2015 / 12:18