Seite 1 von 2
Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Freitag 31. Januar 2014, 14:15
von sia
Hallo Leute!
Ich bin neu hier im Forum und habe mich zunächst einmal etwas in den bereits existierenden Themen umgeschaut; bin aber leider nicht fündig geworden!
Ich arbeite noch nicht so lange mit Python und stehe relativ weit am Anfang. Daher komme ich bei folgendem Problem nicht weiter.
Ich habe mehrere Dateien.. Nennen wir sie mal D_1, D_2, D_3 usw. ich aus jeder dieser Dateien die achte Zeile in eine einzelene txt-Datei kopieren. Den umgekehrten Weg bin ich bereits geganegn und habe es geschafft aus einer Datei mehere Dateien zu erstellen. Doch irgendwie schaffe ich es nicht, aus mehreren Dateien eine bestimmte Zeile in eine neue Datei zu kopieren!
Lieben Gruß
Sia
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Freitag 31. Januar 2014, 14:31
von Hyperion
sia hat geschrieben:Den umgekehrten Weg bin ich bereits geganegn und habe es geschafft aus einer Datei mehere Dateien zu erstellen. Doch irgendwie schaffe ich es nicht, aus mehreren Dateien eine bestimmte Zeile in eine neue Datei zu kopieren!
Sehr sonderbar, da Du für den einen Fall bereits alles an Handwerkszeug kennst, was Du für den anderen benötigst...
Evtl. zeigst Du uns mal Deine Versuche und wirst einmal ein wenig konkreter, was die Daten anbelangt. (Also zeig uns wirklich ein Beispiel)
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Freitag 31. Januar 2014, 14:52
von 123gro
Vielleicht geht das wenn du die datei irgendwie in einen String umwandelst
und dann kann man ja einen String in "Scheiben" schneiden z.B.
wort="Hose"
wort[0:2]
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Freitag 31. Januar 2014, 15:16
von BlackJack
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python
from itertools import islice
def main():
with open('output.txt', 'w') as out_file:
line_number = 7 # Counting starts at 0.
for filename in ['d1.txt', 'd2.txt', 'd3.txt']:
with open(filename, 'r') as lines:
out_file.writelines(islice(lines, line_number, line_number + 1))
if __name__ == '__main__':
main()
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Freitag 31. Januar 2014, 17:46
von sia
Hello..
Danke für Eure schnelle Antwort. Ich habe hier mal meinen Code, mit dem der besagte umgekehrte Weg begangen wurde:
Code: Alles auswählen
import numpy as np
import string
import os
s = np.genfromtxt('t_start.dat', unpack=True, dtype = int)
p = np.genfromtxt('t_stop.dat', unpack=True, dtype = int)
n = np.genfromtxt('number.dat', unpack=True, dtype = int)
for h in range(s.size):
tmin = str(s[h])
tmax = str(p[h])
num = str(n[h])
print tmin,tmax
fobj_in = open("LC_Nebel_default.conf")
fobj_out = open("LC_Nebel"+"_"+num,"w")
contents = fobj_in.readlines()
contents.insert(35, '\ttag = LAT_SED_'+tmin+"_"+tmax)
contents = "".join(contents)
fobj_out.write(contents)
for line in fobj_in:
fobj_out.write(line.rstrip()+"\n")
fobj_out.write ('\ttmin = '+tmin +"\n")
fobj_out.write ('\ttmax = '+tmax)
fobj_out.close()
fobj_in.close()
Also.. Die Datei LC_Nebel_default wird kopiert und der Inhalt wird in die Dateien LC_Nebel_1, LC_Nebel_2, LC_Nebel_3, ... usw. Kopiert. Ausserdem wird in die erstellten Dateien in Zeile 35 nach einer TAB-Taste "tag = LAT... eingefügt".. In jeder durchnummerierten LC_Nebel-Datei wird aus t_start und t_stop unten die entsprechenden Zeile hinzugefügt.

Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Freitag 31. Januar 2014, 21:07
von BlackJack
@sia: Ein paar Anmerkungen zu dem Quelltext:
Einrücktiefe ist per Konvention vier Leerzeichen pro Ebene.
Die Importierten Module `string` und `os` werden überhaupt nicht verwendet.
Einbuchstabige Namen sind in der Regel keine gute Idee. So ein Name soll dem Leser verraten was der Wert dahinter im Kontext des Programms bedeutet. Arrays `s`, `n`, und `p` zu nennen hilft dabei nicht. Und `h` ist auch ein ungewöhnlicher Name für eine Laufvariable die als Index verwendet wird.
Die Datei mit der immer gleichen Vorlage für jeden Schleifendurchlauf neu zu öffnen und einzulesen ist unnötige Arbeit. Die Daten kann man einmal *vor* der Schleife einlesen.
Zeile 15 liest die komplette Datei als Zeilen in eine Liste. Darum machen die Zeilen 19 und 20 überhaupt keinen Sinn weil damit nichts mehr aus der Datei gelesen werden kann. Wenn das ginge, wäre der `rstrip()`-Aufruf mit anschliessendem Ergänzen eines Zeilenendes wahrscheinlich auch nicht sehr sinnvoll.
An der Stelle sollte man auch überlegen ob man ``LC_Nebel_default.conf`` nicht als Template-Datei anlegt, zum Beispiel in dem man `string.Template` dafür verwendet, oder Platzhalter für einen `format()`-Aufruf in den Text der Datei einfügt.
Zeichenkettenformatierung sollte man auch dem Zusammensetzen von Zeichenketten und Werten mittels `str()` und ``+`` vorziehen, das ist übersichtlicher. Beim erstellen des Ausgabenamens ist das verketten von zwei literalen Zeichenketten mittels ``+`` unsinnig.
Ist das Absicht das die letzte Zeile der Ausgabedatei nicht mit einem Zeilenende-Zeichen abgeschlossen ist? Einige Werkzeuge können mit solchen Dateien Probleme bereiten.
Machen die `numpy`-Arrays überhaupt Sinn? Wenn ich das richtig sehe wird der Inhalt aus Textdateien, also Zeichenketten, in Zahlen umgewandelt, nur um die sofort wieder in Zeichenketten umzuwandeln.
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Freitag 31. Januar 2014, 22:45
von sia
@BlackJack:
Danke für deine Tipps..! Ich weiß, dass mein Quellcode ästhetisch nicht das ansprechendste ist.

Doch ich musste unbeabsichtigt diesen Weg über Python gehen. Daher musste ich schnell eine Lösung finden, um meine Ausgangsdatei 500 mal zu kopieren und dabei zu achten, dass sie immer anders heißen und die letzten beiden Zeilen tmin und tmax enthalten. Es hat funktioniert..^^ Und dabei ist es beabsichtigt, dass am Ende kein Satzschlusszeichen oder so steht. Ebenso müssen die Dateien mit 1,2,3,.. usw. enden, weil das so vom Cluster verlangt wird!:)
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Samstag 1. Februar 2014, 11:35
von BlackJack
Das hätte man auch ungefähr so schreiben können (ungetestet):
Code: Alles auswählen
#!/usr/bin/env python
from itertools import izip
def iter_stripped_lines(filename):
with open(filename) as lines:
for line in lines:
yield line.strip()
def main():
with open('LC_Nebel_default.conf') as template_file:
template = template_file.read()
filenames = ['number.dat', 't_start.dat', 't_stop.dat']
for number, t_min, t_max in izip(*map(iter_stripped_lines, filenames)):
print t_min, t_max
with open('LC_Nebel_' + number, 'w') as out_file:
out_file.write(template.format(t_min=t_min, t_max=t_max))
if __name__ == '__main__':
main()
Warum Du das mit den Zahlen am Ende des Dateinamens erwähnst verstehe ich jetzt nicht. Es sei denn Du hast die Bemerkung zum Ausgabedateinamen falsch verstanden. Du hast dort nicht nur einen Wert drangepappt sondern auch *literale* Zeichenketten mit ``+`` zusammengesetzt, was keinen Sinn macht das unnötig kompliziert zu schreiben.
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Samstag 1. Februar 2014, 12:06
von sia
Ja, du hast recht.. das + muss vor dem num nicht hin

. Ich war froh, dass die Ausgabedateien mit ..._1, ..._2 ..usw. enden. Das ist auch so gewollt, dass die Datei mit einer Zahl endet.

Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Samstag 1. Februar 2014, 12:25
von BlackJack
@sia: Irgendwie habe ich immer noch das Gefühl Du hast den Punkt nicht verstanden, denn vor dem `num` muss natürlich ein ``+`` stehen, sonst wäre das ein Syntaxfehler. Du hast geschrieben ``'LC_Nebel' + '_' + num`` und da ist das Zusammensetzen von 'LC_Nebel' und '_', statt es gleich zusammen zu schreiben, unsinnig hoch drei.
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Samstag 1. Februar 2014, 14:36
von sia
Achsoo.. Ja, klar..!

Jetzt weiß ich, was du meinst.. Es ginge ja auch einfach 'LC_Nebel_' +num..! (Wie Du ja bereits vorgeschlagen hattest..!:))
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Mittwoch 5. Februar 2014, 14:56
von sia
Hallo BlackJack,
du hattest relativ weit am Anfang einen ungetesteten Weg gepostet. Bekomme dabei einen Syntax-Fehler:
with open ('output.txt', 'w') as out_file:
^
SyntaxError: invalid syntax
Ich weiss nicht, woran das liegen mag!
Lieben Gruss
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Mittwoch 5. Februar 2014, 15:09
von pillmuncher
sia hat geschrieben: with open ('output.txt', 'w') as out_file:
^
SyntaxError: invalid syntax
Ich weiss nicht, woran das liegen mag!
Entweder, du hast in den Zeilen davor ein öffnende Klammer ohne die dazu gehörende schließende, oder du verwendest Python < 2.6, wo es das with-Statement noch nicht gab. Bei Python 2.5 kannst du es verwenden, sofern du in deinem Modul ganz oben (nach dem shebang) die Zeile
einfügst.
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Mittwoch 5. Februar 2014, 15:35
von sia
@Pillmuncher
Python-Version ist 2.4.3
Gibt es dafuer auch eine Loesung?

(..ausser Update. Kommt leider nicht in Frage)
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Mittwoch 5. Februar 2014, 15:37
von BlackJack
@sia: Eine neuere installieren.

Python 2.5 ist mittlerweile 8 Jahre alt.
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Mittwoch 5. Februar 2014, 15:50
von sia
@BlackJack:
Ich weiss, dass ein Update ueberfaellig ist

Ich sitze aber an einem Rechner der Uni und da kann ich nicht sehr viel an der Software aendern. Zu Hause sollte es dann klappen

Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Mittwoch 5. Februar 2014, 16:09
von EyDu
Du könntest dort eine aktuelle Version in deinem Benutzerverzeichnis kompilieren.
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Mittwoch 5. Februar 2014, 16:58
von sia
@EyDu: Danke.
@Alle: Das Problem ist jetzt mit einem Shell-Skript geloest worden!

Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Freitag 7. Februar 2014, 14:39
von sia
Falls es jemanden noch interessieren koennte:
Es gibt da soetwas schoenes wie 'grep' habe ich als shell-skript laufen lassen
Code: Alles auswählen
for file in `ls *results`
do
tmin=`grep tmin $file | awk '{print $2}'`
tmax=`grep tmax $file | awk '{print $2}'`
Integral=`grep \^Integral $file | awk '{print $2}'`
dIntegral=`grep -P 'dIntegral\t' $file | awk '{print $2}'`
t=`echo \($tmin+$tmax\)/2 | bc`
echo $t $Integral $dIntegral
done
Damit durchsucht man alle Dateien, die mit "results" enden nach tmin (grep tmin $file | awk '{print $2}') wobei in der Originaldatei tmin = 123456 steht. mit awk nimmt man sich 123456 heraus. Anschliessend kann man mit > outputfile.txt alle in eine Datei reinschreiben.
Liebe Gruesse
Sia
Re: Zeile aus mehreren Dateien in eine neue Datei kopieren
Verfasst: Freitag 7. Februar 2014, 21:20
von BlackJack
@sia: Kleine Maneuverkritik:
Die Backticks ` sind nicht besonders gut lesbar und verschachteln kann man sie auch nicht. Stattdessen würde ich die äquivalente $(…)-Syntax verwenden. Weiterer Pluspunkt: man kann ``$(…)`` direkt in "-Zeichenketten verwenden.
Über ``$(ls pattern)`` zu iterieren ist falsch. Sowie in den Dateinamen irgendwas ”komisches” vorkommt fällt man damit auf die Nase. Korrekt wäre es ganz einfach nur das Muster zu verwenden, also in Deinem Fall ``for file in *results``.
Ebenfalls wegen möglicher Sonderzeichen, da fallen auch schon ansonsten harmlose Leerzeichen drunter, sollte man immer wenn man ``$file`` verwendet doppelte Anführungszeichen setzen, damit das auch ganz sicher nur *ein* Argument ist.
Wenn bei ``bc`` die Nachkommestallen gar nicht benutzt werden und das ganze am ende in einer Bash läuft, kann man `$t` auch die Shell ausrechnen lassen. Da kommt bei mir am Ende das hier heraus (ungetestet):
Code: Alles auswählen
#!/usr/bin/bash
for file in *results
do
tmin=$(grep 'tmin' "$file" | awk '{print $2}')
tmax=$(grep 'tmax' "$file" | awk '{print $2}')
Integral=$(grep '\^Integral' "$file" | awk '{print $2}')
dIntegral=$(grep -P 'dIntegral\t' "$file" | awk '{print $2}')
t=$(echo "($tmin + $tmax) / 2" | bc)
# alternativ in Bash:
# t=$((($tmin + $tmax) / 2))
echo "$t $Integral $dIntegral"
done
Was hier aber immer noch nahezu ein Verbrechen ist: Jede Datei wird *vier* mal komplett von Anfang bis Ende nach jeweils einem Wert durchsucht und jedes mal wird ``awk`` auf eine Zeile angewendet, nur um das Feld aus der Zeile zu extrahieren. Wenn man sowieso schon AWK als Abhängigkeit hat, kann man *das* auch gleich verwenden um das gesamte Problem zu lösen. Genau für solche Aufgaben ist es ja gedacht. Ungetestet:
Code: Alles auswählen
#!/usr/bin/env awk
/tmin/ { tmin = $2 }
/tmax/ { tmax = $2 }
/^Integral/ { integral = $2 }
/dIntegral\t/ { d_integral = $2 }
END { print (tmin + tmax) / 2, integral, d_integral }
Ich habe einfach mal die regulären Ausdrücke aus dem Shell-Skript übernommen, da würde man hier vielleicht etwas spezifischere Tests auf Feldwerte machen wollen.