|
bernd_heller
Anmeldungsdatum: 21. November 2010
Beiträge: Zähle...
|
Hallo zusammen, wie kann ich eine Textdatei mit einem shell script einlesen und formatiert ausgeben. In der Quelldatei stehen mehrere Datensätze untereinander, diese möchte ich in eine csv Datei so speichern, dass je ein Datensatz in einer Zeile steht. Quelle:
Vorname Nachname Beruf PLZ Ort Kunde
Ziel:
Vorname, Nachname, Beruf, PLZ, Ort, Kunde dann ein Zeilenumbruch und weiter mit Zeile 2 Die Punkte gehören nicht in die Datei, sie dienen hier nur zur Formatierung. Mein erster Versuch: (Danke an das Forum) | while read line
do
echo "$line"
done < test.txt
|
Mit read komme ich aber nicht weiter, deshalb meine Frage
wie kann ich das lösen?
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
Gibt es Trennmarken zwischen den Einträgen oder kann man das so sehen, dass er einfach je 5 aufeinander folgende Zeilen mit Kommata getrennt zusammenkleben soll? In dem Fall könnte man z.B. paste nutzen, ein - liest jeweils eine Zeile:
$ cat customers.txt
Hans
Maulwurf
Moleman
5555
Springfield
ja
Homer
Simpson
Sicherheitsinspektor in Sektor 7 G
5555
Springfield
nein
$ paste - - - - - - -d, < customers.txt
Hans,Maulwurf,Moleman,5555,Springfield,ja
Homer,Simpson,Sicherheitsinspektor in Sektor 7 G,5555,Springfield,nein
|
|
bernd_heller
(Themenstarter)
Anmeldungsdatum: 21. November 2010
Beiträge: Zähle...
|
Hallo seahawk1986 danke für die Antwort.
Gibt es Trennmarken zwischen den Einträgen oder kann man das so sehen, dass er einfach je 5 aufeinander folgende Zeilen mit Kommata getrennt zusammenkleben soll?
Es ist ein wenig komplizierter denn es kann sein das Felder nicht gefüllt sind. Wenn ich die Daten auslesen kann müsste ich mit einer if Schleife entscheiden ob eine neue Zeile beginnt oder nicht.
Sicher ist aber das am Ende immer eine 0 oder eine 1 kommt daran kann ich fest machen das eine neue Zeile beginnen soll. So ungefähr: | if [ wert == 0 or 1 ]
then
Zeilenumbruch
fi
|
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13242
|
Ansonsten natürlich mit awk: | awk '{printf "%s", $1} NR%6==0 {printf "\n"} NR%6!=0 {printf ","} END {printf "\n"}' datei
|
|
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11278
|
bernd_heller schrieb: Es ist ein wenig komplizierter denn es kann sein das Felder nicht gefüllt sind.
Wenn das einer leeren Zeile entspricht, wäre das ja kein Problem. Falls nicht kommt die Reihenfolge der Spalten für die csv-Datei durcheinander. Wenn ich die Daten auslesen kann müsste ich mit einer if Schleife entscheiden ob eine neue Zeile beginnt oder nicht.
Sicher ist aber das am Ende immer eine 0 oder eine 1 kommt daran kann ich fest machen das eine neue Zeile beginnen soll.
Wenn du es als Bash-Schleife haben willst, die Zeilen zusammenfügt, bis eine 0 oder 1 allein in einer Zeile steht:
| while read -r line; do
echo -n "$line"
[[ "$line" =~ ^[0-1]$ ]] && echo "" || echo -n ","
done < test.txt
|
|
|
bernd_heller
(Themenstarter)
Anmeldungsdatum: 21. November 2010
Beiträge: Zähle...
|
Danke seahawk1986, danke rklm,
das funktioniert beides schon ganz gut. Werde mir heute Abend nochmal Gedanken machen. Eventuell muss dich die Importdatei noch mal verändern,damit es keine Spaltenverschiebung kommt wenn Felder nicht gefüllt sind. Gruß Bernd
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13242
|
bernd_heller schrieb:
Werde mir heute Abend nochmal Gedanken machen. Eventuell muss dich die Importdatei noch mal verändern,damit es keine Spaltenverschiebung kommt wenn Felder nicht gefüllt sind.
Du darfst auf jeden Fall keine Leerzeilen weglassen, es sei denn, es gibt ein Verfahren (z.B. regulärer Ausdruck), mit dem man die erste Zeile eines Datensatzes verlässlich erkennen kann. Sonst hat man keine Chance, die Eingabe korrekt zu parsen! Meine Version mit awk zählt einfach, so dass da Leerzeilen kein Problem sind.
|
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
|
bernd_heller schrieb: ...
Sicher ist aber das am Ende immer eine 0 oder eine 1 kommt daran kann ich fest machen das eine neue Zeile beginnen soll.
Mit dieser Vorgabe könntest Du Deine Daten auch recht bequem mit sed auswerten: track@track:~$ echo 'Hans
Maulwurf
Moleman
5555
Springfield
1
Homer
Simpson
Sicherheitsinspektor in Sektor 7 G
5555
Springfield
0' | sed -n '1h; 1!H; /^[01]$/ {g; s/\n/,/gp; n;h}'
Hans,Maulwurf,Moleman,5555,Springfield,1
Homer,Simpson,Sicherheitsinspektor in Sektor 7 G,5555,Springfield,0 Dabei sammle ich jeweils die Zeilen im "Hold Space", bis die Zeile mit 0 oder 1 kommt, und gebe dann alles aus. (mit "," statt Zeilenumbrüchen) bernd_heller schrieb: ... Werde mir heute Abend nochmal Gedanken machen. Eventuell muss dich die Importdatei noch mal verändern,damit es keine Spaltenverschiebung kommt wenn Felder nicht gefüllt sind.
Wenn Du die Importdatei sowieso selber erstellst, dann frage ich mich allerdings, warum Du sie dabei nicht gleich richtig formatierst ... Oder ist das so ein unmögliches Exportprogramm, dass das nicht geht ? LG, track
|
|
bernd_heller
(Themenstarter)
Anmeldungsdatum: 21. November 2010
Beiträge: Zähle...
|
Ich drehe mich hier im Kreis, jedes mal wenn ich ein Lösung für ein Problem gefunden habe taucht an anderer Stelle das nächste auf. Meine Idee die der Lösung am nächsten kommt ist folgende: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #!/bin/bash
i=0
while read -r line; do
i=$(( $i + 1 ))
if [[ "$line" =~ ^[0-1]$ ]]
then
i=0
echo ""
elif [ $i -eq "3" ] && [ "$line" != "Arbeitnehmer" ] # zweite Bedingung Arbeitgeber fehlt
then
echo -n ",Leer, $line"
else
echo -n ", $line"
fi
done < test.txt
|
Meine Quelldatei sieht so aus: 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
26
27
28 | Fred
Kalinowski
Arbeitnehmer
04.03.1970
1
Chantal
Schroeder
Arbeitnehmer
13.09.1993
0
Andy
Pipkin
29.08.1980
1
Gerlinde
Kalinowski
01.01.1967
0
Emma
Jane
Arbeitnehmer
24.03.1995
0
Emily
Black
Arbeitgeber
05.08.2000
0
|
An dritter Stelle kommt Arbeitnehmer / Arbeitgeber. Die Angabe fehlt aber hier und da und deshalb habe ich mir überlegt das mit einem Zähler zu lösen. Wenn Zähler = 3 und Wert <> Arbeitgeber dann füge "Leer" ein. Bei dieser Lösung habe ich aber ein Komma vor den Zeilen. Wenn wirklich noch jemand Lust hat mir zu helfen, ich wäre sehr Dankbar dafür. Danke Gruß Bernd
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13242
|
bernd_heller schrieb:
Wenn wirklich noch jemand Lust hat mir zu helfen, ich wäre sehr Dankbar dafür.
Ich sehe das Problem, dass Du auf einige Frage gar nicht eingehst. Das reduziert üblicherweise die Motivation der Helfer...
|
|
bernd_heller
(Themenstarter)
Anmeldungsdatum: 21. November 2010
Beiträge: Zähle...
|
Sorry wenn ich Fragen offen gelassen haben sollte, war der Meinung das ich alles so gut es geht erklärt habe. Danke an alle helfenden für die Mühe die ihr euch gemacht habt.
|
|
apt-ghetto
Anmeldungsdatum: 3. Juni 2014
Beiträge: 2943
|
Mit deinen Beispieldaten habe ich ein Perlskript geschrieben, das dir eventuell helfen könnte: 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 | #!/usr/bin/perl -w
# mitarbeiterInCsv.pl ---
use warnings;
use strict;
my $datei = "mitarbeiter.txt";
my $csv = "mitarbeiter.csv";
my ($in_fh, $out_fh);
my $out = $datei;
$out =~ s/(\.\w+)?$/.out/;
if (! open $in_fh, '<', $datei) {
die "Kann '$datei' nicht oeffnen: $!";
}
if (! open $out_fh, '>', $out) {
die "Kann nicht in '$out' schreiben: $!";
}
while (<$in_fh>) {
chomp;
$_ .= '%';
s/\A(0|1)%\Z/$1\n/;
print $out_fh $_;
}
close $in_fh;
close $out_fh;
if (! open $in_fh, '<', $out) {
die "Kann '$out' nicht oeffnen: $!";
}
if (! open $out_fh, '>', $csv) {
die "Kann nicht in '$csv' schreiben: $!";
}
while (<$in_fh>) {
chomp;
my @fields = split /%/, $_;
if (defined $fields[2] && $fields[2] =~ /\d+.\d+.\d+/) {
$fields[4] = $fields[3];
$fields[3] = $fields[2];
$fields[2] = 'Leer';
}
foreach (@fields) {
print $out_fh "$_,";
}
print $out_fh "\n";
}
close $in_fh;
close $out_fh;
|
Anpassen musst du die Variablen $datei und $csv. Auf die Datei $datei mit deinen Eingabedaten wird nur lesend zugegriffen und es werden zwei Dateien erstellt. Die eine mit *.out als Endung, dient nur als Zwischendatei und die Datei mit *.csv ist die Ausgabedatei. Deine Eingabedatei darf das Zeichen % nicht enthalten. Das Skript basiert auf deinen Beispieldaten. Im Startpost hast du die Datenstruktur anders angegeben als in deinen Beispieldaten.
|
|
bernd_heller
(Themenstarter)
Anmeldungsdatum: 21. November 2010
Beiträge: Zähle...
|
Im Startpost hast du die Datenstruktur anders angegeben als in deinen Beispieldaten.
Ja, ich war beim ersten Post noch nicht ganz im klaren was ich brauche. Dein Perlscript läuft bestens, leider verstehe ich nicht alles. Ich werde mir die einzelnen Schritte genauer ansehen damit ich auch weiß was ich mache. Vielen Dank dafür.
|
|
apt-ghetto
Anmeldungsdatum: 3. Juni 2014
Beiträge: 2943
|
Da es gestern schon sehr spät war und ich eigentlich schon lange im Bett hätte sein wollen, habe ich auf ausführliche Erklärungen verzichtet. Das interessante/wichtige passiert in den beiden while-Schleifen. In der ersten wird ein Datensatz auf eine Zeile gepackt, getrennt durch das Trennzeichen % (das Ergebnis siehst du in *.out). In der zweiten Schleife wird jede Zeile in einzelne Felder getrennt und in ein Array geschrieben. Dann schaust du, ob dort wo Arbeitnehmer oder Arbeitgeber sein sollte, ein Datum ist und passt dein Array entsprechend an. Anschliessend schreibst du jedes Feld mit einem angehängten Komma in die CSV-Datei.
|
|
bernd_heller
(Themenstarter)
Anmeldungsdatum: 21. November 2010
Beiträge: 61
|
Danke für die Erklärung. Mit Perl habe ich keine Erfahrung, deshalb ist es nicht so leicht zu lesen wie ich finde. Bisher habe ich nur etwas mit Python und PHP gespielt. Gruß Bernd
|