Extraindo apenas múltiplos padrões específicos do arquivo

0

Eu tenho o seguinte arquivo:

 $less dummyKeyAndValue.txt
   apiKey=key1;some_other_data;term=abc
   apiKey=key2;some_other_data;some_other_data;term=def
   term=pqr;some_other_data;apiKey=key1
   apiKey=key3;some_other_data;term=def

Eu quero a saída da seguinte forma:

 $less dummyNewFile.txt
   apiKey=key1 term=abc
   apiKey=key2 term=def
   apiKey=key1 term=pqr
   apiKey=key3 term=def

Principalmente, eu quero extrair 'apiKey' e 'term' do arquivo dummyKeyAndValue.txt, ambos podem aparecer em diferentes ordens no arquivo. Eu tentei seguir o comando:

   $cat dummyKeyAndValue.txt | tee >(egrep -o 'apiKey=[a-zA-Z0-9]+')  |   
   egrep -o 'term=[a-zA-Z]+' | less

Eu recebo a saída como:

     term=abc
     term=def
     term=pqr
     term=def

Alguém pode me ajudar com o comando para obter a saída desejada?

    
por Gunjan Aswani 02.01.2017 / 14:09

3 respostas

0

Como alternativa, uma solução muito eficiente, mas um pouco mais complicada

sed 'G;s/;/\n/' | awk -F= '
$1~/apiKey/ {key=$2}
$1~/term/ {term=$2}
/^$/ {printf("  apiKey=%s term=%s\n", key, term)
      key=""
      term=""}'

Primeiro, sed é usado para fazer duas coisas: O comando "G" adicionará efetivamente uma linha aberta após cada "conjunto de registros" e, em segundo lugar, o comando "substituto" ( s/;/\n/ ) expandirá efetivamente cada conjunto de registros a ser um por linha, substituindo cada ; por um caractere de nova linha. O que sai do sed são os pares de valor-chave, um por linha, com uma linha aberta designando o final de cada registro.

Então o awk precisa apenas olhar o primeiro campo para encontrar os atributos nos quais você está interessado e o segundo campo para o valor, o que elimina a necessidade de index e substr. Uma vez que o awk encontra uma "linha aberta", imprime os valores que encontrou. Para resiliência, você pode "limpar" os valores no final de cada registro. Observe o uso de -F= para instruir o awk a dividir a linha em campos com base no = -sign.

$1 ~ /.../ significa "Quando o primeiro campo corresponde ao valor /.../

Em seguida, ele atribui um valor a uma variável (chave ou termo)

O /^$/ significa "quando o awk encontra uma linha aberta"

    
por 02.01.2017 / 16:40
1

Esta solução baseada no awk pode ajudar porque é mais fácil de ler / manter. O awk geralmente é a ferramenta preferida para analisar valores semelhantes a colunas de um arquivo de texto.

/tmp$ cat a.awk
{
   keypart=substr($0, index($0, "apiKey=")+7)
   keyvalue=substr(keypart, 1, index(keypart, ";")-1)

   termpart=substr($0, index($0, "term=")+5)
   termvalue=substr(termpart, 1, index(termpart, ";")-1)

# If the attribute is last on the input line there will be no ; to mark the end so use the whole part
   if(keyvalue=="") {keyvalue=keypart}
   if(termvalue=="") {termvalue=termpart}
   printf ("  apikey=%s term=%s\n", keyvalue, termvalue)
}

O script Awk (chamado a.awk acima, mas qualquer nome de arquivo que o sense makse possa ser usado) pode ser usado assim:

awk -f a.awk inputfile

Como você pode ver, eu cuido do caso de um campo de entrada que termina no final da linha, especialmente com uma declaração if para cada um. Eu aprimoraria esse script da seguinte forma para lidar automaticamente com esses casos:

/tmp$ cat a.awk  
{
   LINE=$0 ";"

   keypart=substr(LINE, index(LINE, "apiKey=")+7)
   keyvalue=substr(keypart, 1, index(keypart, ";")-1)

   termpart=substr(LINE, index(LINE, "term=")+5)
   termvalue=substr(termpart, 1, index(termpart, ";")-1)

   printf ("  apikey=%s term=%s\n", keyvalue, termvalue)
}

O benefício disso fica mais claro quando você adiciona mais casos!

    
por 02.01.2017 / 16:21
0

Provavelmente não é muito eficiente, mas se você quiser seguir sua abordagem de 'dois greps', você pode fazer isso usando paste :

$ paste <(grep -o 'apiKey=[^;]*' dummyKeyAndValue.txt) <(grep -o 'term=[^;]*' dummyKeyAndValue.txt)
apiKey=key1     term=abc
apiKey=key2     term=def
apiKey=key1     term=pqr
apiKey=key3     term=def

Ou a abordagem do KISS, usando o GNU sed :

sed -nE -e 's/(apiKey=[^;]*).*(term=[^;]*)/ /p' \
  -e 's/(term=[^;]*).*(apiKey=[^;]*)/ /p' dummyKeyAndValue.txt
    
por 02.01.2017 / 14:25