Fractionner le fichier et le mettre dans la structure de données correspondante?


10

J'ai un fichier qui contient la seule ligne ci-dessous:

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

dans lequel j'ai deux jeux de données:

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

Maintenant, je dois lire le fichier ci-dessus et le diviser de manière à pouvoir extraire les informations de chaque machine comme mentionné ci-dessus et les stocker dans une structure de données.

Actuellement, je ne sais pas quelle structure de données je devrais utiliser dans un script shell bash. Si je faisais cela en Java, j'utiliserais Map<String, Set<String>>mais je ne sais pas quoi utiliser dans un script shell.

Et après l'avoir stocké dans une structure de données, je dois l'itérer et imprimer le résultat.

Je peux lire le fichier ci-dessus en utilisant le script shell ci-dessous:

#!/bin/bash

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

Mais je ne sais pas comment diviser les données de ligne ci-dessus de manière à pouvoir extraire les informations de chaque machine et les stocker dans une structure de données?

METTRE À JOUR:-

Voici mon script shell que j'ai obtenu après avoir suivi la suggestion de 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

Réponses:


4

les structures de données bash sont trop rudimentaires pour des tableaux même à 2 dimensions. Êtes-vous sûr que c'est l'outil que vous souhaitez utiliser?

Avec bash et GNU grep, vous pouvez faire ce désordre désagréable:

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

C'est assez fragile. J'utiliserais Perl pour quelque chose comme ça: toujours moche mais plus concis

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
                        ]
        };

Merci pour la suggestion. Je pourrais aller avec l'option de script shell car finalement j'ai besoin d'utiliser scp donc je crois que faire scp dans un script shell sera facile. Mais de toute façon, voyons comment cela se passe. J'ai mis à jour ma question avec le script shell réel que j'utiliserais après avoir incorporé votre suggestion. Veuillez jeter un coup d'œil et faites-moi savoir si cela semble correct et s'il y a quelque chose que vous souhaitez modifier, faites-le moi savoir également.
SSH

+1 Mouvement assez lisse avec le eval, là-bas.
Joseph R.

1

Les utilitaires de traitement de texte du shell sont principalement conçus pour manipuler des données représentées avec un enregistrement par ligne et des champs séparés par des espaces ou un caractère fixe. Ce format est complètement différent et vous ne pourrez pas le traiter de manière simple.

Une approche consiste à prétraiter le fichier pour l'adapter au type de format qui peut être traité facilement. Je suppose que les crochets et les accolades ne sont pas utilisés autrement que ceux décrits ici (accolades autour du texte entier, crochets autour des listes de valeurs de la machine).

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

Le résultat a une machine par ligne et des virgules pour séparer les enregistrements. L'extrait suivant analyse le nom de l'ordinateur sur chaque ligne et laisse une liste de valeurs séparées par des virgules values.

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

L'extrait de code bash suivant place les valeurs dans un tableau.

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

@Giles: Merci pour la suggestion. Est-il également possible d'obtenir le nombre total de fichiers pour chaque machine? ce qui signifie le nombre total en utilisant la même commande ci-dessus? Comme, par exemple ci-dessus, machineA a quatre fichiers et machineB a également quatre fichiers
SSH

@SSH Voir mon montage.
Gilles 'SO- arrête d'être méchant'

0

Vous pouvez utiliser awkpour terminer la tâche.

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]

Merci John. Est-il possible d'obtenir également le nombre total de fichiers pour chaque machine. Comme, par exemple ci-dessus, machineA a quatre fichiers et machineB a également quatre fichiers. Est-il possible d'obtenir cela également?
SSH

0

Cela ressemble un peu à JSON. Vous pouvez le corriger en JSON approprié et utiliser les outils 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"
   ]
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.