staging.inyokaproject.org

textdatei einlesen und formatiert ausgeben

Status: Gelöst | Ubuntu-Version: Ubuntu 17.10 (Artful Aardvark)
Antworten |

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)

1
2
3
4
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:

1
2
3
4
if [ wert == 0 or 1 ]
  then
    Zeilenumbruch 
fi

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Ansonsten natürlich mit awk:

1
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:

1
2
3
4
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 Team-Icon

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

Avatar von 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 Team-Icon

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

Antworten |