Dividir o arquivo e colocá-lo na estrutura de dados correspondente?

10

Eu tenho um arquivo que contém a única linha abaixo:

{machineA=[0, 1024, 4, 1028], machineB=[1, 1025, 5, 1029]}

em que tenho dois conjuntos de dados:

machineA=[0, 1024, 4, 1028]
machineB=[1, 1025, 5, 1029]

Agora, eu preciso ler o arquivo acima e dividi-lo de tal forma que eu possa extrair as informações de cada máquina como mencionado acima e armazená-las em alguma estrutura de dados.

Atualmente, estou confuso com qual estrutura de dados devo usar em um script de shell bash. Se eu estivesse fazendo isso em Java, usaria Map<String, Set<String>> , mas não sei o que devo usar em um script de shell.

Depois de armazená-lo em alguma estrutura de dados, preciso iterar e imprimir o resultado.

Eu posso ler o arquivo acima usando o script de shell abaixo:

#!/bin/bash

while read -r line; do
       echo "$line"
    done < data.txt

Mas não tenho certeza de como dividir os dados da linha acima de modo que eu possa extrair cada informação da máquina e armazená-la em alguma estrutura de dados?

ATUALIZAÇÃO: -

Abaixo está o meu shell script que eu tenho depois de seguir a sugestão dada por glenn -

#!/bin/bash

while read -r line; do
       echo "$line"
       declare -A "$(
            echo "x=("
            grep -oP '(\w+)(?==)|(?<==\[).*?(?=\])' <<< "$line" |
              tr -d , |
              paste - - |
              sed 's/^/[/; s/\t/]="/; s/$/"/'
            echo ")"
        )"

        for key in "${!x[@]}"; do           # need quotes here
            for element in ${x[$key]}; do   # no quotes here
                printf "%s\t%s\n" "$key" "$element"
            done
        done    
    done < primary.txt
    
por SSH 17.12.2013 / 01:50

4 respostas

4

As estruturas de dados do bash são muito rudimentares para matrizes bidimensionais. Tem certeza de que esta é a ferramenta que você deseja usar?

Com o bash e o GNU grep, você pode fazer essa bagunça desagradável:

line='{machineA=[0, 1024, 4, 1028], machineB=[1, 1025, 5, 1029]}'
declare -A "$(
    echo "x=("
    grep -oP '(\w+)(?==)|(?<==\[).*?(?=\])' <<< "$line" |
      tr -d , |
      paste - - |
      sed 's/^/[/; s/\t/]="/; s/$/"/'
    echo ")"
)"

for key in "${!x[@]}"; do           # need quotes here
    for element in ${x[$key]}; do   # no quotes here
        printf "%s\t%s\n" "$key" "$element"
    done
done
machineA    0
machineA    1024
machineA    4
machineA    1028
machineB    1
machineB    1025
machineB    5
machineB    1029

Isso é muito frágil. Eu usaria o Perl para algo assim: ainda feio, mas mais conciso

echo "$line" | perl -MData::Dumper -ne '
    s/=\[/=>[/g; 
    eval "\$x=$_";
    # do something with your data structure (a hash of arrays) 
    print Dumper($x)
'
$VAR1 = {
          'machineB' => [
                          1,
                          1025,
                          5,
                          1029
                        ],
          'machineA' => [
                          0,
                          1024,
                          4,
                          1028
                        ]
        };
    
por 17.12.2013 / 02:38
1

Os utilitários de processamento de texto do shell são projetados principalmente para manipular dados representados com um registro por linha e campos separados por um espaço em branco ou por um caractere fixo. Este formato é completamente diferente e você não poderá processá-lo de maneira direta.

Uma abordagem é pré-processar o arquivo para se ajustar ao tipo de formato que pode ser processado facilmente. Eu suponho que colchetes e chaves não são usados de qualquer outra forma que não seja retratada aqui (chaves ao redor de todo o texto, colchetes ao redor das listas de valores da máquina).

<data.txt sed -e 's/^{//' -e 's/}$//' -e 's/ *= *\[/,/g' -e 's/, */,/g' -e 's/\] *$//' -e 's/] *, */\n/g'

O resultado tem uma máquina por linha e vírgulas para separar registros. O snippet a seguir analisa o nome da máquina em cada linha e deixa uma lista de valores separados por vírgulas em values .

… | while IFS=, read -r machine values; do …

O seguinte trecho específico do bash coloca os valores em uma matriz.

… | while IFS=, read -r -a values; do
  machine=${values[0]}; shift values
  echo "There are ${#values[@]} on machine $machine"
done
    
por 17.12.2013 / 02:43
0

Você pode usar awk para concluir a tarefa.

awk -F "], " '/[a-zA-Z]=\[[0-9]/ {gsub(/{|}/,""); for(i=1; i<=NF; i++) if($i !~ /\]$/) print $i"]"; else print $i}' data.txt

machineA=[0, 1024, 4, 1028]
machineB=[1, 1025, 5, 1029]
    
por 17.12.2013 / 07:41
0

Isso parece um pouco com o JSON. Você pode corrigi-lo para ser um JSON adequado e usar ferramentas JSON:

$ echo '{machineA=[0, 1024, 4, 1028], machineB=[1, 1025, 5, 1029]}' |  perl -pe 's!\b!"!g; s/=/:/g' | json_pp
{
   "machineB" : [
      "1",
      "1025",
      "5",
      "1029"
   ],
   "machineA" : [
      "0",
      "1024",
      "4",
      "1028"
   ]
}
    
por 17.12.2013 / 10:06