Encontre uma string em uma seção de um arquivo com várias seções

1

Como sed / awk para uma string contida em outra string.

TESTVAR='
{
 icon : "icons/773_l.png",
 id : 80,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 requestType : "UUID",
 version : 79
}
,
{
 icon : "thisicon",
 id : 8080,
 initialState : false,
 isPng : true,
 label : "Boundaries",
 opacity : 1,
 requestType : "NothingSpecial",
 version : 8
}

Eu preciso selecionar o version : 79 para o objeto que contém requestType : "UUID" . Como eu selecionaria tudo dentro do primeiro bloco, depois selecionaria a versão e teria apenas um comando return 79 . Eu tenho tentado há algum tempo, mas não sei como selecionar apenas tudo entre o primeiro {} . Depois disso, eu precisaria obter o número depois de version : .

Eu achei que isso funcionaria, mas não foi awk '/\{/{f=1;next}/\}/{f=0}f' test.txt

Além disso, o pedido não é garantido. Então eu realmente preciso selecionar tudo dentro de { e } contendo "UUID". Em seguida, selecione version : \([0-9]+\)

Isso é próximo, mas muito ganancioso: sed -e 's/{\(.*UUID.*\)}//' test.txt

    
por kosmos 25.09.2014 / 18:57

3 respostas

1

Primeiro, o que vem à minha mente não é nem sed nem awk:

$ tr -d '\n' < file | grep -Po 'requestType : "UUID"\K.*? version : \K[0-9]*'
79

Provavelmente pode ser feito com mais facilidade, especialmente se você puder garantir que "version" vem logo após "requestType".

No caso, se version não precisar ir atrás de requested Type , as coisas serão um pouco mais complicadas:

$ tr -d '\n' < file | grep -Po '{.[^}]*?requestType : "UUID".*?}' | grep -Po 'version : \K[0-9]*'
79

Se houver mais seções que correspondam a todas elas, serão impressas:

$ cat file
TESTVAR='
{
 icon : "icons/773_l.png",
 id : 80,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 version : 79,
 requestType : "UUID"
}
,
{
 icon : "thisicon",
 id : 8080,
 initialState : false,
 isPng : true,
 label : "Boundaries",
 opacity : 1,
 requestType : "NothingSpecial",
 version : 8
}
,
{
 icon : "icons/773_l.png",
 id : 80,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 requestType : "UUID",
 version : 87
}
,
{
 icon : "icons/773_l.png",
 id : 80,
 version : 17,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 requestType : "UUID"
}
,
{
 icon : "thisicon",
 id : 8080,
 requestType : "NothingSpecial",
 initialState : false,
 label : "Boundaries",
 opacity : 1,
 version : 18,
 isPng : true
}

$ tr -d '\n' < file | grep -Po '{.[^}]*?requestType : "UUID".*?}' | grep -Po 'version : \K[0-9]*'
79
87
17
    
por 25.09.2014 / 19:35
1

o awk permite que você defina o separador de registro, então, em vez de uma nova linha (cada linha é um registro), use "} \ n" como o final do registro:

echo "$TESTVAR" |
gawk -v RS="}\n" '
    /requestType : "UUID"/ && match($0, /version : ([0-9]+)/, m) {print m[1]}
'
79

Isto é específico do GNU awk, para a função match ().

Pena que este não é um JSON válido. Então você poderia usar um analisador JSON:

jq '(.[] | select(.requestType == "UUID")).version' <<JSON
[
 {
  "icon" : "icons/773_l.png",
  "id" : 80,
  "initialState" : true,
  "isPng" : false,
  "label" : "Imagery",
  "opacity" : 1,
  "requestType" : "UUID",
  "version" : 79
 }
 ,
 {
  "icon" : "thisicon",
  "id" : 8080,
  "initialState" : false,
  "isPng" : true,
  "label" : "Boundaries",
  "opacity" : 1,
  "requestType" : "NothingSpecial",
  "version" : 8
 }
]
JSON
    
por 25.09.2014 / 20:42
1

Aqui está uma maneira de fazer isso com sed :

$ sed -rn '/\{/{:a;N;/\}/{/requestType : "UUID"/s/.*version : ([0-9]+).*//p;d};ba}' <<< "$TESTVAR"
79
$ 

Esta é uma adaptação do link para seus dados.

Você menciona que esta é uma estrutura de dados javascript, então eu acho que o método mais confiável para analisar seria usando javascript. Eu instalei o Node.js para fazer isso, mas suponho que qualquer interpretador de javascript de linha de comando possa fazer algo assim:

$ echo "arr=[$TESTVAR]; console.log(arr.filter(function(elem) { return elem.requestType === \"UUID\"; })[0].version)" | node
79
$ 

Aviso de isenção

Você precisa ter certeza dos dados aqui. Eu não conheço javascript tão bem, mas acho que a injeção de código seria bem possível se a string de dados de entrada fosse criada corretamente.

    
por 25.09.2014 / 20:25