Datei teilen und in entsprechende Datenstruktur einfügen?


10

Ich habe eine Datei, die die folgende einzelne Zeile enthält:

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

in dem ich zwei Datensätze habe:

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

Jetzt muss ich die obige Datei lesen und so aufteilen, dass ich die Informationen der einzelnen Maschinen wie oben erwähnt extrahieren und in einer Datenstruktur speichern kann.

Derzeit bin ich verwirrt, welche Datenstruktur ich in einem Bash-Shell-Skript verwenden soll. Wenn ich dies in Java tun würde, würde ich verwenden, Map<String, Set<String>>aber ich bin nicht sicher, was ich in einem Shell-Skript verwenden soll.

Und nachdem ich es in einer Datenstruktur gespeichert habe, muss ich es iterieren und das Ergebnis ausdrucken.

Ich kann die obige Datei mit dem folgenden Shell-Skript lesen:

#!/bin/bash

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

Ich bin mir jedoch nicht sicher, wie ich die obigen Zeilendaten so aufteilen soll, dass ich jede Maschineninformation extrahieren und dann in einer Datenstruktur speichern kann.

AKTUALISIEREN:-

Unten ist mein Shell-Skript, das ich erhalten habe, nachdem ich dem Vorschlag von glenn gefolgt bin -

#!/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

Antworten:


4

Bash-Datenstrukturen sind selbst für zweidimensionale Arrays zu rudimentär. Sind Sie sicher, dass dies das Tool ist, das Sie verwenden möchten?

Mit Bash und GNU Grep können Sie dieses unangenehme Durcheinander anrichten:

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

Das ist ziemlich zerbrechlich. Ich würde Perl für so etwas verwenden: immer noch hässlich, aber prägnanter

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

Danke für den Vorschlag. Ich könnte mich für die Shell-Skript-Option entscheiden, da ich schließlich scp verwenden muss, damit ich glaube, dass es einfach sein wird, scp im Shell-Skript auszuführen. Aber wie auch immer, mal sehen, wie das geht. Ich habe meine Frage mit dem tatsächlichen Shell-Skript aktualisiert, das ich möglicherweise verwende, nachdem ich Ihren Vorschlag aufgenommen habe. Bitte werfen Sie einen Blick darauf und lassen Sie mich wissen, ob es richtig aussieht und ob Sie etwas ändern möchten, dann lassen Sie es mich auch wissen.
SSH

+1 Ziemlich schlauer Zug mit dem eval, da.
Joseph R.

1

Die Shell-Textverarbeitungsprogramme dienen in erster Linie dazu, Daten zu bearbeiten, die mit einem Datensatz pro Zeile und Feldern dargestellt werden, die entweder durch Leerzeichen oder ein festes Zeichen getrennt sind. Dieses Format ist völlig anders und Sie können es nicht einfach verarbeiten.

Ein Ansatz besteht darin, die Datei so vorzuverarbeiten, dass sie dem Format entspricht, das leicht verarbeitet werden kann. Ich gehe davon aus, dass Klammern und Klammern nicht anders als hier dargestellt verwendet werden (Klammern um den gesamten Text, Klammern um Maschinenwertelisten).

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

Das Ergebnis enthält eine Maschine pro Zeile und Kommas zum Trennen von Datensätzen. Das folgende Snippet analysiert den Computernamen in jeder Zeile und hinterlässt eine durch Kommas getrennte Liste von Werten in values.

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

Das folgende Bash-spezifische Snippet fügt die Werte in ein Array ein.

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

@ Giles: Danke für den Vorschlag. Ist es auch möglich, die Gesamtzahl der Dateien für jeden Computer abzurufen? was bedeutet die Gesamtzahl mit dem gleichen obigen Befehl? Wie im obigen Beispiel hat Maschine A vier Dateien und Maschine B hat auch vier Dateien
SSH

@SSH Siehe meine Bearbeitung.
Gilles 'SO - hör auf böse zu sein'

0

Sie können verwenden awk, um die Aufgabe abzuschließen.

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]

Danke John. Ist es möglich, die Gesamtzahl der Dateien für jeden Computer abzurufen? Wie im obigen Beispiel hat Maschine A vier Dateien und Maschine B hat auch vier Dateien. Ist es möglich, das auch zu bekommen?
SSH

0

Das sieht ein bisschen wie JSON aus. Sie können das Problem mit JSON beheben und JSON-Tools verwenden:

$ 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"
   ]
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.