Hi Leute, ich bin neu hier und vesuche gerade mich in Python einzuarbeiten.
Könnte mir jemand helfen folgendes Perl command in Python umzubauen?
Zur Erklarung: Aus einem Text file sollen einfach die letzten Zeichen abgeschnitten werden, möchte aber kein Programm dazu schreiben sondern alles an der Unix shell machen. Das Perl-Commad lautet
cat Textfile.txt|perl -pe 's#(.*)(\d{6})#$1#' > Textfile.fixed
Das ist ( so ähnlich) im textfile eine Zeile und die letzen 6 Stellen aller Zeilen ( also das Datum: 201803 ) soll abgeschnitten/gelöscht werden:
12345656789345 5567 F345 123456400 0 0085201803
Wie würde ich das als Unix/Pyton Einzeiler schreiben?
Ich hoffe, Ihr könnt mir helfen
Gruß
python an der Unix shell mit cat command; umsetzten eines Perl Befehls nach Python
@dark_universe: Python ist nicht ganz so kryptisch wie Perl, heißt, man muß da etwas ausführlicher programmieren. Weißt Du was Perl da macht? Das muß man dann durch explizites Lesen von der Standardeingabe und dem matchen eines Regulären Ausdrucks machen. Python-Einzeiler gibt es nicht.
- DeaD_EyE
- User
- Beiträge: 1017
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Ich denke das käme dem Perl Snippet am nächsten:
Dann das Programm mit der Pipe verknüpfen:
Mit awk wäre es kürzer. Neben awk gibt es noch nützliche tools wie z.B. cut und tr.
Ich bin damals vom Shell-Scripting weg, weil es mir zu viel Zeichensalat geworden ist.
Perl ist da nochmal eine Ecke kryptischer.
Code: Alles auswählen
import sys
import os
import re
regex = re.compile(r'.*(\d{6})$')
if not os.isatty(sys.stdin.fileno()):
for line in sys.stdin:
match = regex.search(line)
if match:
print(match.group(1))
Code: Alles auswählen
cat DATEI | python3 dein_filter.py
Ich bin damals vom Shell-Scripting weg, weil es mir zu viel Zeichensalat geworden ist.
Perl ist da nochmal eine Ecke kryptischer.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
-
- User
- Beiträge: 7
- Registriert: Dienstag 20. März 2018, 12:08
Damit müsste es doch gehen: <(...) denotes process substitution. Das kommt dem ziemlich nahe kommt was ich brauche:
script.py <(awk '{if ($4 == 1975) print $1,$2,$3}' input.txt)
- für script.py muss ein Python 3 da sein
- das <( leitet die Übergabe an ein Unix comand ein wie awk, grep oder sed
- in dem Bsp. werden alle Zeilen ausgegeben, die in der 4. Spalte ein 1975 haben
Allerdings scheitere ich schon daran, das spript.py aufzurufen. Python 3 liegt bei uns im /opt/.../python3 Verzeichnis.
Das inputfile sieht so aus:
D000001 D000001 44 1975
D000001 D000408 1 1983
D000001 D000641 1 1977
D000001 D000900 27 1975
Das awk komado alleine liefert
D000001 D000001 44
D000001 D000900 27
und der Python Teil schreibt das ganze in ein file? Hier brauche ich mal eure weitere Hilfe, damit mal das Bsp. läuft und dann gehts mit meinem Problem weiter.
Danke
script.py <(awk '{if ($4 == 1975) print $1,$2,$3}' input.txt)
- für script.py muss ein Python 3 da sein
- das <( leitet die Übergabe an ein Unix comand ein wie awk, grep oder sed
- in dem Bsp. werden alle Zeilen ausgegeben, die in der 4. Spalte ein 1975 haben
Allerdings scheitere ich schon daran, das spript.py aufzurufen. Python 3 liegt bei uns im /opt/.../python3 Verzeichnis.
Das inputfile sieht so aus:
D000001 D000001 44 1975
D000001 D000408 1 1983
D000001 D000641 1 1977
D000001 D000900 27 1975
Das awk komado alleine liefert
D000001 D000001 44
D000001 D000900 27
und der Python Teil schreibt das ganze in ein file? Hier brauche ich mal eure weitere Hilfe, damit mal das Bsp. läuft und dann gehts mit meinem Problem weiter.
Danke
Mit Python geht das auch kurz und knapp:
Angenommen obigen Code speicherst Du als 'fix.py' ab, dann führst Du das aus mit
'$ python fix.py < textfile.txt > textfile.fixed'
Falls Du die Shebang-Zeile gesetzt und die Datei als executable markiert hast, kannst Du auch die Extension weg lassen:
'./fix < textfile.txt > textfile.fixed'
Dies gilt für Dein erstes Beispiel, die letzten sechs Zeichen zu entfernen. Das kannst Du natürlich beliebig modifizieren oder auch gegen mögliche Fehler absichern.
Code: Alles auswählen
import sys
for line in sys.stdin:
sys.stdout.write(line.rstrip()[:-6] + '\n')
'$ python fix.py < textfile.txt > textfile.fixed'
Falls Du die Shebang-Zeile gesetzt und die Datei als executable markiert hast, kannst Du auch die Extension weg lassen:
'./fix < textfile.txt > textfile.fixed'
Dies gilt für Dein erstes Beispiel, die letzten sechs Zeichen zu entfernen. Das kannst Du natürlich beliebig modifizieren oder auch gegen mögliche Fehler absichern.
-
- User
- Beiträge: 7
- Registriert: Dienstag 20. März 2018, 12:08
Ok, vielen Dank, werde ich heute ausprobieren
-
- User
- Beiträge: 7
- Registriert: Dienstag 20. März 2018, 12:08
So, hat geklappt, habe die Lsg von kbr mit line.rstrip()[:-6] umgestzt. Die konnte ich einfach nachvollziehen, das von DeaD_EyE war mir erst mal zu komplziert.
Danke auch an die anderen, die mir Wertvolle Tipps gegeben haben.
Gruß
Danke auch an die anderen, die mir Wertvolle Tipps gegeben haben.
Gruß
-
- User
- Beiträge: 168
- Registriert: Montag 9. Mai 2016, 09:14
- Wohnort: Berlin
Hallo,
mit sed geht das auch!
Wobei zu beachten ist, dass mit der Option -i, die Änderungen direkt übernommen werden.
[codebox=bash file=Unbenannt.bsh]
sed -i -r 's/(.*)[A-Z0-9 ]{6}$/\1/' test.txt
[/code]
mit sed geht das auch!
Wobei zu beachten ist, dass mit der Option -i, die Änderungen direkt übernommen werden.
[codebox=bash file=Unbenannt.bsh]
sed -i -r 's/(.*)[A-Z0-9 ]{6}$/\1/' test.txt
[/code]
-
- User
- Beiträge: 7
- Registriert: Dienstag 20. März 2018, 12:08
Hallo nochmal,
bei genauem Betrachten der Lsg, von kbr mit line.rstrip()[:-6] gibt es noch 2 Probleme.
1. in jedem Zeilenende gibt es ein ^M ( 00123654321^M) das ich gerne erhalten möchte/muß oder am Ende wieder hinzufügen muss.
2. Jedes file das ich bearbeiten muss hat einen
a) Header,
b) dann kommen die Daten, wo jetzt die letzen 6 Zeichen gelöscht werden sollen
c) einen Trailer.
Header und Tailer sollen nicht verändert werden, die Datengröße oder besser die Anzahl der Zeilen dazwischen sind variabel, also mal 1000 Zeilen mal 50 000 Zeilen.
Wie würde ich da vorgehen? Erst mal die Zeilen der Datei zählen und dann erste und letzte Zeile von der Bearbeitung ausschließen?
Danke und Gruß
bei genauem Betrachten der Lsg, von kbr mit line.rstrip()[:-6] gibt es noch 2 Probleme.
1. in jedem Zeilenende gibt es ein ^M ( 00123654321^M) das ich gerne erhalten möchte/muß oder am Ende wieder hinzufügen muss.
2. Jedes file das ich bearbeiten muss hat einen
a) Header,
b) dann kommen die Daten, wo jetzt die letzen 6 Zeichen gelöscht werden sollen
c) einen Trailer.
Header und Tailer sollen nicht verändert werden, die Datengröße oder besser die Anzahl der Zeilen dazwischen sind variabel, also mal 1000 Zeilen mal 50 000 Zeilen.
Wie würde ich da vorgehen? Erst mal die Zeilen der Datei zählen und dann erste und letzte Zeile von der Bearbeitung ausschließen?
Danke und Gruß
@dark_universe: das ^M kommt daher, dass Du DOS/Windows-Zeilenenden hast. Einfach statt '\n' -> '\r\n' schreiben. Bisher ignorierst Du ja Header und Trailer und löscht einfach die letzten 6 Ziffern, die Du in jeder Zeile findest (egal ob sie am Zeilenende stehen oder nicht). Sauberer wäre es dann tatsächlich, Header und Trailer gesondert zu behandeln. Woher erkennt man denn, was Header und was Trailer ist?
Code: Alles auswählen
sed -rn 's/(.+)[[:digit:]]{6}$/\1/;p' path/to/your/inputfile
Und sed sollte auf so ziemlich jedem *nix verfügbar sein.
@IHack: das funktioniert nicht, wenn, wie der OP sagt, ein Carriage-Return am Ende jeder Zeile steht. Einfacher wäre es dann auch, einfach nur die letzten 6 Zahlen durch nichts zu ersetzen:
[codebox=bash file=Unbenannt.sh]
sed -rn 's/[[:digit:]]{6}\s*$//;p' path/to/your/inputfile[/code]
[codebox=bash file=Unbenannt.sh]
sed -rn 's/[[:digit:]]{6}\s*$//;p' path/to/your/inputfile[/code]
-
- User
- Beiträge: 7
- Registriert: Dienstag 20. März 2018, 12:08
@Sirius3:
Header und Trailer erkennt man nicht so einfach. Man weiss das sie am Anfang/Ende sind.
Deswegen würde ich wie folgt vorgehen für sagen wir mal 1000 files mit jeweils 100 - 100 000 Zeilen:
1. File1 öffnen und und Zeilen zählen: erste Zeile ist n, letzte nMax -> erste Schleife
2. for- Schleife mit dem Script vonb kbr:
import sys
for line in sys.stdin:
sys.stdout.write(line.rstrip()[:-6] + '\n')
und in der Schleife von n+1 bis nMax-1 laufen lassen
3. beide Schleifen schliessen
4. File2 öffnen und weiter gehts ...
Könnt Ihr mir mal helfen, wie dazu das äussere Phyton Programmier-Gerüst auszusehen hat, das wäre klasse.
Header und Trailer erkennt man nicht so einfach. Man weiss das sie am Anfang/Ende sind.
Deswegen würde ich wie folgt vorgehen für sagen wir mal 1000 files mit jeweils 100 - 100 000 Zeilen:
1. File1 öffnen und und Zeilen zählen: erste Zeile ist n, letzte nMax -> erste Schleife
2. for- Schleife mit dem Script vonb kbr:
import sys
for line in sys.stdin:
sys.stdout.write(line.rstrip()[:-6] + '\n')
und in der Schleife von n+1 bis nMax-1 laufen lassen
3. beide Schleifen schliessen
4. File2 öffnen und weiter gehts ...
Könnt Ihr mir mal helfen, wie dazu das äussere Phyton Programmier-Gerüst auszusehen hat, das wäre klasse.
@dark_universe: Ob header und tailer einfach oder schwer zu erkennen sind, ist völlig egal. Wenn sie vorhanden sind, musst Du sie erkennen. Sonst kannst Du keine Fallunterscheidung bezüglich der zu bearbeitenden Zeilen treffen.
Wenn Du weißt, dass der header genau eine Zeile beträgt, dann ist das kein Problem – Du überspringst die Zeile einfach. Beim trailer ist das anders: da brauchst Du eine Mustererkennung. Oder, falls der trailer auch nur eine Zeile beträgt, pufferst Du die zu bearbeitende Zeile zunächst, um zu sehen, ob noch eine weitere nachfolgt. Eigentlich eine prima Übung.
Wenn Du weißt, dass der header genau eine Zeile beträgt, dann ist das kein Problem – Du überspringst die Zeile einfach. Beim trailer ist das anders: da brauchst Du eine Mustererkennung. Oder, falls der trailer auch nur eine Zeile beträgt, pufferst Du die zu bearbeitende Zeile zunächst, um zu sehen, ob noch eine weitere nachfolgt. Eigentlich eine prima Übung.