derRote92
Anmeldungsdatum: 25. März 2020
Beiträge: 7
|
Hallo zusammen, Ich habe ursprünglich zwei Dateien. Diese beiden Dateien vergleiche ich mittels "comm -12 d1 d2 >d3" auf Überschneidungen und lasse mir das Ergebnis des Vergleichs als dritte Datei ausgeben. Die Ergebnis-Vergleichsdatei besteht nur aus einer Spalte aber sehr vielen Zeilen. Das Ergebnis des Vergleichs ist mir vorher nicht bekannt, deswegen kann ich im Vorfeld nicht sagen wieviele Zeilen die Ergebnis-Vergleichsdatei enthalten wird. Nehmen wir an die Ergebnis-Vergleichsdatei enthält Namen: Franziska Frühling
Siegfried Sommer
Herbert Herbst
Werena Winter
etc. Ich möchte nun, dass jede einzelne Zeile einer Variable zugeordnet wird, damit ich den Inhalt der Variablen, also die Namen in einem anderen Zusammenhang weiterverarbeiten kann. Folgende Überlegung brachte hier nicht das gewünschte Ergebnis. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #!/bin/bash
declare -i x
x=1
for i in `cut -f 1 Ergebnis-Vergleichsdatei`
do
Name$x=$i
let x=$x+1
done
echo $v1
|
Ich hoffe ihr könnt mir weiterhelfen. Gruß
der Rote Bearbeitet von rklm: Codeblock bitte auch für Dateiinhalte nutzen
|
Doc_Symbiosis
Anmeldungsdatum: 11. Oktober 2006
Beiträge: 4378
Wohnort: Göttingen
|
Du kannst Dir eine Datei einfach in ein Array einlesen (seit Bash 4.0):
readarray -t Name < d3 Das Array durchlaufen kannst Du dann so
for i in "${Name[@]}"; do
echo $i;
done
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12802
|
Herzlich willkommen hier im Forum! derRote92 schrieb:
Ich möchte nun, dass jede einzelne Zeile einer Variable zugeordnet wird, damit ich den Inhalt der Variablen, also die Namen in einem anderen Zusammenhang weiterverarbeiten kann.
Ich versuche ja immer zu optimieren und außerdem bin ja ein neugieriger Mensch, also: wie willst Du die Daten denn weiter verarbeiten?
|
derRote92
(Themenstarter)
Anmeldungsdatum: 25. März 2020
Beiträge: 7
|
rklm schrieb: Herzlich willkommen hier im Forum! derRote92 schrieb:
Ich möchte nun, dass jede einzelne Zeile einer Variable zugeordnet wird, damit ich den Inhalt der Variablen, also die Namen in einem anderen Zusammenhang weiterverarbeiten kann.
Ich versuche ja immer zu optimieren und außerdem bin ja ein neugieriger Mensch, also: wie willst Du die Daten denn weiter verarbeiten?
Hallo schonmal vielen Dank für eure Antworten ! Ich werde es auch sofort ausprobieren. Das eigentliche Vorhaben habe ich eigentlich gar nicht geschildert, da es etwas komplexer ist. Ausgangspunkt sind zwei Dateien also ein Grunddatensatz und ein Vergleichsdatensatz. Beide Dateien enthalten verschiedene Inhalte, die aber identisch aufgebaut sind also von den Spalten her also Name, Adresse, Telefonnummer, E-Mail und noch weitere Angaben. Logischerweise ist jede Zeile ein Datensatz. Ziel ist es Datensätze aus dem Vergleichsdatensatz dem Grunddatensatz zuzuordnen, da angegeben Parameter übereinstimmen - also eine Schnittmengenanalyse. Für die Zuordnung müssen jedoch nicht alle Parameter übereinstimmen, sondern es muss nur ein gewisser Schwellenwert überschritten sein, damit die einzelnen Datensätze dem Grunddatensatz zugeordnet werden können. So gehen wir nun von dem aus, was ich mit meinem ersten Post geschrieben habe: Ich habe meinen Grunddatensatz und meinen Vergleichsdatensatz und nutze dann eben die Codezeilen: | #!/bin/bash
cut -f 1 Grunddatensatz >d1
cut -f 1 Vergleichsdatensatz >d2
comm -12 d1 d2 >d3
|
Wie zu sehen ist, nehme ich mir aus beiden Datensätzen jeweils nur die erste Spalte, lasse sie mir in separaten Dateien ausgeben und gleiche diese Hilfsdateien auf Übereinstimmungen ab, welche dann in Datei d3 ausgegeben werden. So das Problem ist aber, dass ich dann die Übereinstimmungen z.B. in den Namen in der separaten Datei d3 habe und nicht im Vergleichsdatensatz. Also ist es meine Überlegung gewesen die Übereinstimmenden Namen im Vergleichsdatensatz mit einer Art Markierung zu versehen, also Herbert Herbst soll den Zusatz Herbert Herbst_§ bekommen, da er ja in beiden Datensätzen vorkommt. Dieses bisher geschilderte Procedere läuft dann für alle Angaben wie Adresse, E-Mail, etc. ebenfalls durch. Am Ende wollte ich mir dann für jede Zeile ausgeben lassen wie oft die Zeichenfolge "_§" in jeder Zeile vorkommt und wenn die Anzahl den Schwellwert übersteigt, kann ich diese Datenzeile aus dem Vergleichsdatensatz dem Grunddatensatz zuordnen. Daher aber die Übereinstimmungen aus Grund- und Vergleichsdatensatz nun in Datei d3 liegen, ich sie aber effektiv im Vergleichsdatensatz benötige, ergab sich die Frage mit den Variablen, denn wenn ich die Daten aus d3 in Variablen habe sollen eben genau die Werte in den Variablen im Vergleichsdatensatz herausgesucht werden und durch $Variable1_§ ersetzt/erweitert werden, dass soll "sed" dann machen. Das habe ich eigentlich vor. Wenn jemand von euch aus meinem Vorhaben eine viel einfachere Lösung entwickeln kann, wäre ich sehr dankbar, das ist nur der Lösungsweg, den ich mir überlegt habe. Schonmal vielen Dank für eure Hilfe! Gruß
der Rote
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12802
|
derRote92 schrieb: Auf den ersten Blick klingt das wie eine Aufgabe für eine relationale Datenbank - und wenn es SQLite ist. Möglicherweise geht das auch mit einer Tabellenkalkulation. Aber ich glaube, ich habe noch nicht genau verstanden, was Du eigentlich willst.
Ausgangspunkt sind zwei Dateien also ein Grunddatensatz und ein Vergleichsdatensatz. Beide Dateien enthalten verschiedene Inhalte, die aber identisch aufgebaut sind also von den Spalten her also Name, Adresse, Telefonnummer, E-Mail und noch weitere Angaben. Logischerweise ist jede Zeile ein Datensatz. Ziel ist es Datensätze aus dem Vergleichsdatensatz dem Grunddatensatz zuzuordnen, da angegeben Parameter übereinstimmen - also eine Schnittmengenanalyse. Für die Zuordnung müssen jedoch nicht alle Parameter übereinstimmen, sondern es muss nur ein gewisser Schwellenwert überschritten sein, damit die einzelnen Datensätze dem Grunddatensatz zugeordnet werden können.
Du beschreibst weiter unten, wie Du den Schwellwert berechnen willst. Kannst Du aber mal beschreiben, was der Schwellwert ausdrücken soll?
Wie zu sehen ist, nehme ich mir aus beiden Datensätzen jeweils nur die erste Spalte, lasse sie mir in separaten Dateien ausgeben und gleiche diese Hilfsdateien auf Übereinstimmungen ab, welche dann in Datei d3 ausgegeben werden. So das Problem ist aber, dass ich dann die Übereinstimmungen z.B. in den Namen in der separaten Datei d3 habe und nicht im Vergleichsdatensatz. Also ist es meine Überlegung gewesen die Übereinstimmenden Namen im Vergleichsdatensatz mit einer Art Markierung zu versehen, also Herbert Herbst soll den Zusatz Herbert Herbst_§ bekommen, da er ja in beiden Datensätzen vorkommt. Dieses bisher geschilderte Procedere läuft dann für alle Angaben wie Adresse, E-Mail, etc. ebenfalls durch. Am Ende wollte ich mir dann für jede Zeile ausgeben lassen wie oft die Zeichenfolge "_§" in jeder Zeile vorkommt und wenn die Anzahl den Schwellwert übersteigt, kann ich diese Datenzeile aus dem Vergleichsdatensatz dem Grunddatensatz zuordnen.
Wenn ich Dich richtig verstehe: Das wird so nicht funktionieren, denn Du willst für jede Spalte zählen, wie oft ein Wert im Grunddatensatz vorkommt. Damit können die Treffer auf der anderen Seite in verschiedenen Datensätzen sein. Was Du aber anscheinend eher willst, ist ein Join zwischen den beiden Tabellen, der nur Datensätze zusammenfügt, die mindestens N Übereinstimmungen in den Werten haben. Habe ich das richtig mitgeschnitten? Und dann kommt automatisch die Frage, was passieren soll, wenn es mehrere Vergleichsdatensätze gibt, die auf einen Grunddatensatz matchen: auswelchem Vergleichsdatensatz übernimmst Du dann Werte?
Daher aber die Übereinstimmungen aus Grund- und Vergleichsdatensatz nun in Datei d3 liegen, ich sie aber effektiv im Vergleichsdatensatz benötige, ergab sich die Frage mit den Variablen, denn wenn ich die Daten aus d3 in Variablen habe sollen eben genau die Werte in den Variablen im Vergleichsdatensatz herausgesucht werden und durch $Variable1_§ ersetzt/erweitert werden, dass soll "sed" dann machen.
Mir scheint das eher ein Job für awk ui sein. Aber dazu müssen wir erst mal klären, was genau Du willst. Kannst Du mal ganz abstrakt beschreiben, was der Sinn Deiner Datenverarbeitung ist?
|
derRote92
(Themenstarter)
Anmeldungsdatum: 25. März 2020
Beiträge: 7
|
@rklm schonmal vielen Dank, dass du dir zu meinem Thema Gedanken machst. Um zuerst auf deine Fragen zu Antworten:
Du beschreibst weiter unten, wie Du den Schwellwert berechnen willst. Kannst Du aber mal beschreiben, was der Schwellwert ausdrücken soll?
Der schwellenwert sind die von mir definierte Anzahl an Überschneidungen in den Parametern des Grunddatensatzes mit Parametern im Vergleichsdatensatz. Kannst Du mal ganz abstrakt beschreiben, was der Sinn Deiner Datenverarbeitung ist?
Ziel der Auswertung ist es automatisiert Überschneidungen zwischen beiden Datensätzen zu finden, um die bisher nicht bekannten Datensätze aus dem Vergleichsdatensatz dem Grunddatensatz hinzuzufügen. Zur Ansicht mal ein abstrakter Auszug aus den jeweiligen Datensätzen: Grunddatensatz:
Name Adresse Telefon E-Mail
Franziska Frühling Frühlingsweg 10 0123456789 Frühling@web.de
Siegfried Sommer Sommerstraße 11 9876543210 Sommer@web.de
Herbert Herbst Herbstpfad 12 0123498765 Herbst@web.de
Werena Winter Winterallee 13 9876501234 Winter@web.de Vergleichsdatensatz:
Name Adresse Telefon E-Mail
Franziska Frühling Sommerstraße 10 0123498765 Jahreszeitenmix@web.de So wie vorstehend beschrieben sehen meine Datensätze aus. Es fällt ja auf, dass die Parameter Franziska Frühling
Sommerstraße 10
0123498765 im Vergleichsdatensatz UND im Grunddatensatz enthalten sind, aber eben nicht in dieser Kombination. Darüber hinaus wurde im Vergleichsdatensatz eine bislang unbekannte E-Mailadresse angegeben: Jahreszeitenmix@web.de. Aber eben aufgrund dieser überschneidenden Parameter ist dieser Vergleichsdatensatz dem Grunddatensatz zuzuordnen. Ziel ist es ganz im Grunde ein Skript zu schreiben, dass mir die Maschine sagt: "Ja, der Vergleichsdatensatz gehört zum Grunddatensatz, da hier 3 Parameter (=Schwellwert) übereinstimmen und bitte hier das sind die Datensätze, die den Schwellwert erfüllen." Aktuell mache ich das so wie du gerade, ich schaue es mir an und erkenne die Übereinstimmungen. Die Dateien "Grunddaten" und "Vergleichsdaten" sind aber in Wahrheit 20-50 MB große txt.-Dateien, also wird es schnell unübersichtlich.
|
fleet_street
Top-Wikiautor
Anmeldungsdatum: 30. August 2016
Beiträge: 2130
Wohnort: Hunsrück
|
derRote92 schrieb: … Es fällt ja auf, dass die Parameter Franziska Frühling
Sommerstraße 10
0123498765 im Vergleichsdatensatz UND im Grunddatensatz enthalten sind, …
Entweder Beispiel falsch oder Erklärung, aber es ist trotzdem klar worauf du hinaus willst. 😇
|
derRote92
(Themenstarter)
Anmeldungsdatum: 25. März 2020
Beiträge: 7
|
Ja dann habe ich mich etwas missverständlich ausgedrückt, mein Fehler, entschuldigt bitte ! Was ich eben meinte ist, dass ja der Name, die Adresse und die Telefonnummer für sich einzeln genommen im Grunddatensatz und im Vergleichsdatensatz vorhanden sind und hier nur eine bisher nicht bekannte Kombination der Parameter genutzt wurde, um eine neue Datenzeile zu generieren. Daher aber die einzelnen Parameter (also Name, Adresse, Telefonnummer) schon bekannt sind, kann man es trotzdem dem Grunddatensatz zuordnen. Ich habe mir ja wie gesagt den Lösungsweg schon überlegt, aber für jede andere Lösunng oder überhaupt eine gängige Lösung wäre ich sehr dankbar. Und insgesamt super von Euch, dass ihr mir da weiterhelfen wollt !!!
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12802
|
derRote92 schrieb: Ich habe mir ja wie gesagt den Lösungsweg schon überlegt, aber für jede andere Lösunng oder überhaupt eine gängige Lösung wäre ich sehr dankbar.
Ich glaube, ich habe es verstanden. Du bekommst aber ein Problem mit der Zuordnung, weil Du m.E. doppelte Werte nicht bedacht hast. Einfaches Beispiel G: a d
b e V: a d
a f Jetzt vergleichst Du Spalte 1 und bekommst duch comm eine Datei mit einer Zeile "a". Jetzt weißt Du nicht, ob das die erste oder zweite Zeile in V war. Damit kannst Du die Markierung nicht passend anbringen. M.E. sollte man das komplett im Speicher lösen und eine vollständige Programmiersprache wie Ruby oder Python verwenden. Mein Ansatz wäre folgender. Lese alle Datensätze von V und speichere für jede Spalte einen Index als Map von Wert → Liste von Datensätzen. Lese alle Datensätze von G ein und pro Datensatz Für jeden Wert lese alle V-Datensätze aus dem Index Dabei erzeuge einen temporären Index als Map von Datensatz → Liste mit Spaltennummern, die übereinstimmen Jetzt ermittle den V-Datensatz mit der längsten Liste von Spaltennummern; wenn die Länge mindestens N ist, ist das der beste Treffer.
So ungefähr würde ich das wohl in Ruby schreiben (und in Python geht das auch). Ggf. kannst Du das sogar in awk machen, aber das sieht dann vermutlich ein bisschen hässlich aus.
|
derRote92
(Themenstarter)
Anmeldungsdatum: 25. März 2020
Beiträge: 7
|
Das mit Python geht nicht, da ich in der Netzwerkumgebung kein Phython o.ä. installieren kann. Aber kommen wir doch zurück zu meiner eigentlichen Frage: Ich möchte jede Zeile einer Datei als eigene Variable definieren. Sagt mir doch mal warum das Folgende partout nicht funktionieren will ??? (In der Datei stehen die Namen Zeile für Zeile untereinander) 1
2
3
4
5
6
7
8
9
10
11
12 | #!/bin/bash
declare -i x
x=1
for i in `cut -f 1 Ergebnis_Schnittmenge_Namen`
do
Name_$x=`echo $i | sed -n "$x p" Ergebnis_Schnittmenge_Namen`
let x=$x+1
done
echo $Name_1
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12802
|
derRote92 schrieb: Das mit Python geht nicht, da ich in der Netzwerkumgebung kein Phython o.ä. installieren kann. Aber kommen wir doch zurück zu meiner eigentlichen Frage: Ich möchte jede Zeile einer Datei als eigene Variable definieren. Sagt mir doch mal warum das Folgende partout nicht funktionieren will ??? (In der Datei stehen die Namen Zeile für Zeile untereinander) 1
2
3
4
5
6
7
8
9
10
11
12 | #!/bin/bash
declare -i x
x=1
for i in `cut -f 1 Ergebnis_Schnittmenge_Namen`
do
Name_$x=`echo $i | sed -n "$x p" Ergebnis_Schnittmenge_Namen`
let x=$x+1
done
echo $Name_1
|
Deine Felder enthalten ja Leerzeichen. Allein deswegen geht das mit dem cut in Zeile 5 schon schief. Die Beispieldatei, die Du gezeigt hast, hat ja fixe Spalten. Also musst Du cut anders bedienen um diese sauber zu extrahieren. Aber selbst, wenn Du richtig extrahierst - also die Leerzeichen in den Feldern erhältst - geht das mit der Command Substitution in Zeile 5 schief, weil die dann Wörter trennt und so aus einem Eintrag mit Leerzeichen mehrere macht.
|
dingsbums
Anmeldungsdatum: 13. November 2010
Beiträge: 3532
|
Dein Hauptproblem ist die Struktur der Datensätze. Normalerweise erzeugt man diese mit einem eindeutigen Trennzeichen, welches garantiert in keinem der Felder vorkommt (z.B. Semikolon). Dann kann man die einzelnen Felder sauber auflösen, im Bedarfsfall auf ungültige / unvollständige / fehlerhafte Datensätze prüfen und nach gewünschten Kriterien vergleichen. Nachname;Vorname;PLZ;Ort;Strasse;Hausnummer;Telefon;E-Mail
Frühling;Franziska;99999;Frühlingshausen;Frühlingsweg;10;0123456789;Frühling@web.de
Di Marco;Alessandro;88888;Weitwegstadt;Weitwegweg;88;0887654321;aless.dim@gmx.de
Fehlerteufel;Max;65;Nurweg;+49 3388;fehlerhaft@@@@fehler
|
fleet_street
Top-Wikiautor
Anmeldungsdatum: 30. August 2016
Beiträge: 2130
Wohnort: Hunsrück
|
rklm schrieb: Deine Felder enthalten ja Leerzeichen. Allein deswegen geht das mit dem cut in Zeile 5 schon schief.
Nee, als Standard erwartet cut einen Tabulator als Trennzeichen. Ein Leerzeichen als Trenner müsste man mit -d " " explizit angeben. *Ist doch schön, wenn man auch mal was weiß.* EDIT: In die zweite Zeile ein set -x ins Skript einfügen und es wird gesprächig:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | fleet@Budgie:GNOME–eoan /tmp/topic $ bash skript
+ declare -i x
+ x=1
++ cut -f 1 Ergebnis_Schnittmenge_Namen
+ for i in $(cut -f 1 Ergebnis_Schnittmenge_Namen)
++ echo Franziska
++ sed -n '1 p' Ergebnis_Schnittmenge_Namen
+ Name_1=Franziska Frühling
skript: Zeile 10: Name_1=Franziska: Befehl nicht gefunden
+ let x=1+1
+ for i in $(cut -f 1 Ergebnis_Schnittmenge_Namen)
++ sed -n '2 p' Ergebnis_Schnittmenge_Namen
++ echo Frühling
+ Name_2=Name
skript: Zeile 10: Name_2=Name: Befehl nicht gefunden
+ let x=2+1
+ for i in $(cut -f 1 Ergebnis_Schnittmenge_Namen)
++ echo Name
++ sed -n '3 p' Ergebnis_Schnittmenge_Namen
+ Name_3=
skript: Zeile 10: Name_3=: Befehl nicht gefunden
+ let x=3+1
+ echo
fleet@Budgie:GNOME–eoan /tmp/topic $
|
|
derRote92
(Themenstarter)
Anmeldungsdatum: 25. März 2020
Beiträge: 7
|
Ja, okey. Das hatte ich schon berücksichtigt, auch das i bei der Schleife "for in in Liste" jedes Trennzeichen berücksichtigt und hier jeden Wert nach dem Trennzeichen annimmt d.h. meine Datei "Ergebnis_Schnittmenge_Namen" sieht auch nur so aus, damit die vollständigen Namen nur in eine Variable geschrieben werden: FranziskaFrühling
SiegfriedSommer
HerbertHerbst
WerenaWinter Der Fehler liegt also in der Schleife, insbesondere an der Verkettung von "Name_$x", also bei der Definition der Zählvariable und der Zuordnung von i pro Durchlauf. Erkennt ihn jemand ? @fleet_street: Deine Codezeilen habe ich nicht so ganz verstanden, wie würde denn das richtige fertige Skript (Codezeilen) aussehen ?
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12802
|
fleet_street schrieb: rklm schrieb: Deine Felder enthalten ja Leerzeichen. Allein deswegen geht das mit dem cut in Zeile 5 schon schief.
Nee, als Standard erwartet cut einen Tabulator als Trennzeichen. Ein Leerzeichen als Trenner müsste man mit -d " " explizit angeben.
Guter Punkt. Aber sind das denn Tabs? Wenn so etwas nicht explizit erwähnt wird, dann verlasse ich mich lieber nicht auf den Inhalt im Forum, weil Tabs gerne mal unterwegs verloren gehen - oder auch nicht.
*Ist doch schön, wenn man auch mal was weiß.*
Unbedingt. Ich freue mich auch immer, wenn ich was weiß. ☺
In die zweite Zeile ein set -x ins Skript einfügen und es wird gesprächig:
Wenn Du schon mit bash script aufrufst, dann kannst Du "-x" auch gleich als Argument übergeben. Dann muss man die Datei nicht ändern.
|