• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

[gelöst] alle kleingeschriebenen Zeichen in File löschen

gma

Member
Hallo,

ich habe 20 riesige Files (50-270MB Text) und möchte in diesen

1. alle kleingeschriebenen Zeichen
2 alle "N"-Zeichen

löschen, und zwar in allen bis auf die erste Zeile.

Welches Terminal-basierte Texttool kann das und wie setze ich es ein? Am besten (wegen Speicherknappheit), ohne dass dabei Kopien erstellt werden müssen!

Vielen Dank!
 
A

Anonymous

Gast
Habe ich das Richtig verstanden, es sollen alle Kleinbuchstaben und das Große N gelöscht werden??? Nun hoffe ich mal du hast da jetzt nicht auch noch "äüßö" oder gar noch Zeichen aus anderen Sprachen und Zeichensätzen mit dabei.

Also diese Zeichen einfach erstmal nur wegschneiden ist einfach zB
Code:
tr -d "a-zL" < DATEI
Mit der Maßgabe das die erste Zeile orginal bleiben soll, scheidet der Befehl tr aus, wir nehmen einen neuen sed
Code:
sed '2,$s/[a-zN]//g' DATEI
Das ganze jetzt noch ohne Kopie, :???: wird zum Problem, nicht ganz unlösbar, aber mit Konsol- Mitteln nur äußerst kompliziert zu erzwingen. Da müsste man eine paar Zeilen zB mit C programmieren, das gänge besser und vor allem schneller. Ist auch etwas riskant da bei einem bösen Rechnerunfall sowohl die Neuen als auch die Alten Daten verloren, unvollständig oder korrupt währen.

Wenn du das aber in einer Schleife laufen läßt und nachdem eine Datei fertig ist die orginal-Datei dazu gelöscht wird, solltest du mit dem zusätzlichem Speicherplatz für nur eine solche Datei durchaus auskommen.

Code:
for i in DATEI*
do
 NEUEDATEI="$DATEI".neu
  sed '2,$s/[a-zN]//g' $i > "$NEUEDATEI" && rm "$i" 
done
In dem Fall würden deine neuen Dateien hier noch eine Endung ".neu" erhalten.

Achtung: die Befehle sind nicht getestet, nur aus dem Kopf durch die Finger ins Forum. ;)

robi
 

abgdf

Guru
Hi,

ich würd's in Python machen: Da mußt Du nicht mit RegExes rumhantieren, die sonstwas erfassen.
Ich hoffe, Du hast noch EINMAL 270 MB für eine Datei "out.tmp" im Verzeichnis des Skripts auf Deiner Platte. Dorthin schreibe ich nämlich. Dafür wird die Eingabedatei auch zeilenweise eingelesen, was den RAM-Speicher schont und zudem die Eingabedatei zunächst unangetastet läßt (so daß Du's ausprobieren kannst):
Code:
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

import sys

arg = sys.argv

if len(arg) < 2:
    print "Usage: script.py file.txt"
    sys.exit()

fh1 = file(arg[1], "r")
fh2 = file("out.tmp", "w")

l = True
x = 0

while l:

    l = fh1.readline()

    if x == 0:
        fh2.write(l)
        x += 1
        continue

    b = ""

    for char in l:

        if char.islower() or char == "N":
            continue

        if char in "äöüß":
            continue
       
        b += char

    fh2.write(b)

fh1.close()
fh2.close()
Aber auch hier gilt trotzdem: Benutzung auf eigene Gefahr!

Gruß
 

abgdf

Guru
Uff! Bei solchen Datenmengen muß man doch irgendwie anders denken: Bei 270 MB und zeilenweisem Einlesen hätte man bei 100 Bytes/Zeile
Code:
270 * 1000 * 10 = 2.700.000
Lese- und ebensoviel Schreibzugriffe! Glaub' nicht, daß das die Festplatte mag.
Außerdem wär's in Python wohl zu langsam. Müßte man in C schreiben ...

@gma: Sag doch erstmal, ob

- es tatsächlich um Linux, und nicht etwa um Windows geht,
- wieviel RAM-Speicher Du hast,
- wieviel Festplattenspeicher Du genau dafür zur Verfügung hast,
- wie es mit den deutschen Umlauten sein soll,
- ob es WIRKLICH sein muß (und warum).

Keine Ahnung, ob ich's noch in C umsetzen will ... aber jedenfalls nicht heute :wink:.

Gruß
 
OP
G

gma

Member
Hallo,

vielen, vielen Dank.

Es mit sed zu machen ist absolut ok, es ist schon noch genügend Festplattenplatz vorhanden, ich dachte nur es wäre etwas "schonender" wenn es ohne Duplikation ginge, macht aber nichts.

Ja, system ist opensuse und/oder Mac OS X, also Linux ist schon richtig!
Sprachen: Python kenne ich kaum (kenne mich eigentlich nur mit Perl etwas aus), C geht gar nicht.

Ich dachte, dass integrierte Unix-Werkzeuge schneller als ein Perlskript mit REGEX wären.

Egal, prinzipiell funktioniert es, dauert zwar etwas (insgesamt wird eine Stunde zusammen kommen), ist aber eh nur einmalig!!

Problem: der Befehl

sed '2,$s/[a-zN]//g' DATEI

ersetzt die entsprechenden Zeichen mit Spaces, sie sollen aber entfernt werden! Geht das überhaupt?

nebenbei: habe gerade den wc-Befehl word count benutzt, der scheint mir Line-breaks mitzuzählen, sehe ich das richtig?

gma
 
A

Anonymous

Gast
abgdf schrieb:
Problem: der Befehl

sed '2,$s/[a-zN]//g' DATEI

ersetzt die entsprechenden Zeichen mit Spaces, sie sollen aber entfernt werden! Geht das überhaupt?
Schau mal ob du es richtig geschrieben hast,
Code:
....]//g......   #sollte löschen
....]/ /g......  #würde sie durch ein Space ersetzten
wenn allerdings da viele kleine Worte drin sind, werden diese komplett entfernt aber die Spaces dazwischen bleiben stehen und bilden "lange Schlangen"


robi
 
OP
G

gma

Member
Hallo,

habe

sed '2,$s/[a-zN]//g' Datei

getippt.

Gleiches Ergebnis unter OpenSuse und Mac OS X.

woran kann das liegen?

gma
 
OP
G

gma

Member
sorry, hatte die letzte Antowrt nicht genau genug angeschaut.

Also, die files sehen so aus (sind DNA-Sequenzen):
>identifier
AGCTGCTCGAGCTGAGCTGATCGTAGCTAGCGATGCTagctgtc
gctgctgatcgctgatgctgNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNAGCATAGACATGACAGTA
.......

Also eigentlich ein Wort mit ca 270000000 Buchstaben.

Genau die beschriebenen "Schlangen" bekomme ich, Ergebnis sieht so aus:
>identifier
AGCTGCTCGAGCTGAGCTGATCGTAGCTAGCGATGCT

AGCATAGACATGACAGTA

Gibt es da keine Lösung für, diese "Schlangen" zu entfernen?

gma
 
A

Anonymous

Gast
Das was du beschreibst ist aber etwas anderes als ich erst vermutet habe, das sind leere Zeilen die dann entstehen wenn in einer Zeile vorher nur KLeinbuchstaben oder N stand.
Solche leeren Zeilen kannst du entfernen, wenn sie nicht gebraucht werden.
Code:
sed -e '2,$s/[a-zN]//g' -e '/^$/d' DATEI

Prinzipell geht da mit sed eine ganze Menge, solange du alles immer "eindeutig logisch" beschreiben kannst, sollte es auch eine Lösung geben.
Vielleicht hilft dir dieser Link http://www.linupedia.org/opensuse/Sed selbst den Einstieg in sed zu finden oder herauszufinden was die obrige Zeile genau macht, damit du das entsprechend selbst eventuell noch anpassen kannst.

Ich kann mir schon denken was dich stört, ;) du hättest die Zeilen nach der Ersetztung/ZeichenLöschung so ungefähr alle gleich lang. Sowas geht natürlich auch noch mit sed, aber vergiss das lieber ganz schnell wenn du sed nicht kennst :/ . Das sieht dann ganz schnell mal zB so hier aus. Zeilen sollen alle 20 Zeichen lang werden.
Code:
rob@priv0001:/tmp> cat test1
Überschrift
AGCTGCTCGAGCTGAGCTGATCGTAGCTAGCGATGCTagctgtc
gctgctgatcgctgatgctgNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNAGCATAGACATGACAGTA
rob@priv0001:/tmp> sed -e '2,$s/[a-zN]//g' -e '/^$/d' test1 | sed -e '
1P
1d
:a
/^.\{20\}/!{
        $q
        N
        s/ *\n *//
        ba
}
s/^.\{20\}/&\
/
s/^\(.*\) \(.*\)\n/\1\
\2/
P
s/^.*\n//
ba'
Überschrift
AGCTGCTCGAGCTGAGCTGA
TCGTAGCTAGCGATGCTAGC
ATAGACATGACAGTA
Bei deinen Dateigrößen würde es dir wahrscheinlich den Rechner blockieren, da wahrscheinlich jede Menge Speicher gefressen wird. Außerdem wird das enorm langsam.


robi

PS: habs mal ein bischen getestet und ein wenig optimiert, Ein Versuch währe es dennoch Wert. Folgendes hier aus dem Forum kopieren (nicht abschreiben, das wird nichts)
Code:
#! /bin/sed -f

# formatiert Text auf 80 Zeichen ohne Berücksichtigung von Wortgrenzen
# erste Zeile bleibt unberührt
# Robi@Linux-club.de  Fr 26. Jun 20:23:05 CEST 2009

1P
1d
:a
/^.\{80\}/!{
      $q
      N
      s/ *\n *//
      ba
}
s/^.\{80\}/&\
/
P
s/^.*\n//
ba
Dieses in eine Datei namens testfmt.sed speichern und die Ausführungsrechte darauf vergeben.
Dann vorsichtshalber den Feuerlöscher neben den Rechner stellen und mit einer deiner Dateien folgendes probieren.
Code:
sed -e '2,$s/[a-zN]//g' -e '/^$/d' DATEI | ./testfmt.sed
Wenn der Rechner Feuer fängt oder verdächtig nach Ampere richt dann Stecker ziehen und löschen. ;)

robi
 

abgdf

Guru
robi schrieb:
abgdf hat geschrieben:problem: der Befehl
Nee, war ich nicht, war gma ...
gma schrieb:
sind DNA-Sequenzen
Wow, das hat man ja auch nicht alle Tage. Heißt das, wenn wir falsch skripten, kommt ein anderer Klon oder ein Monster raus :mrgreen: ?
gma schrieb:
kenne mich eigentlich nur mit Perl etwas aus
In Perl könnte das (ohne Lösung des Schlangenproblems) z.B. so aussehen (von der Regex ähnlich wie in sed) (editiert die Datei "in place", ohne sie ganz ins RAM zu laden):
Code:
Hier war ein Vorschlag mit Tie::File; ansonsten s.u.
Gruß
 
A

Anonymous

Gast
abgdf schrieb:
Wow, das hat man ja auch nicht alle Tage. Heißt das, wenn wir falsch skripten, kommt ein anderer Klon oder ein Monster raus :mrgreen: ?

Na bei so viel ersatzlos weggeschnittenen kann da sowieso aus irgendwas Großem maximal nur irgend ein toter Bazillus rausgeclont werden. ;)
Ich nehme mal an, das ist eventuell zum Vergleichen von DNA-Sequenzen zB in der Pflanzenzucht zu gebrauchen. Am Menschen der Zukunft werden die uns hier schon nicht rumspielen lassen. ;) ;) ;) ;)

robi
 
OP
G

gma

Member
Hallo,

habe gerade mal robis sed script getestet:

sed -e '2,$s/[a-zN]//g' -e '/^$/d' DATEI

Bin jetzt zu Hause und habe nur noch Mac OS X zur Hand, liefert leider aber etwas in dieser Art:

CTCTGAGAATGGGGCTCCTGCGGGCCGGCCAGCTTGGGGCCAGAGCCTTC
CGGAGAAGGGCGCGTCCAAGCCCGGGGCGGACGACGGCGGGAAGGCGCTT
CCCTACAGGCGAGAGGAGCAGGCTCGCCCTCTGGTCGTCGGGCCGCGCGC
CCGCAGGTCCCGCCGGGTCACCAGGGCCGCCAGAGGCCGCAGGCGGGCTG
GTGCCTTGGCGGAGA
TGGAAGTGGTACAGCAGCTTCATCTGCGTGTCGCTGGCGGC
GTGGAGCGTCAGGAACTGCACGGCCTCCTGCAGGCACCACGAGTAGCCTT
CGCTGTAGTCCTGGTGCAGGCTCTT
GAACTCGGGGCGCGGGGGGCCCGGGCGCGCTCACCTTTGC
TGTGCTTCAGGTAGCTGACAGCCATCTCCAGGATGTCGGCCTTCTCCAGC
TTGGAGTTGGGCTGGTGCCGCGCGAACTCCTGCTCCAGCAGCAGCTTCAG

Es tauschen also nach wie vor Zeilen auf, die nicht 50 Zeichen aufweisen (meine Files haben 50 Zeichen, es dürfen aber auf keinen Fall mehr als 80 sein).

Was ich nicht sehe, ist ob die Zeilen jetzt mit einem linebreak enden, oder ob da noch Leerzeichen sind. Leerzeichen wären tödlich, linebreaks machen - glaube ich - nichts.

In welchem Editor kann man sich (und wie?) anzeigen lassen, wo tabs, Leerzeichen etc vorhanden sind? Ich benutze unter Suse meißt einfach nur Gedit oder Kate, unter Mac OS X TextWrangler.

gma
 
A

Anonymous

Gast
gma schrieb:
habe gerade mal robis sed script getestet:.......Es tauschen also nach wie vor Zeilen auf, die nicht 50 Zeichen aufweisen (
Du hast ja auch nur die Leerzeilen entfernt. oder ????
Ansonsten Welches der beiden "richtigen" sed-Scripte, das Konsollog , bei dem währe so was eventuell uU auch noch denkbar, aber unten das separate sed-Script sollte eigentlich fehlerfrei laufen.
Wenn du von 80 auf 50 runter willst, beide Zahlen austauschen.


gma schrieb:
Was ich nicht sehe, ist ob die Zeilen jetzt mit einem linebreak enden, oder ob da noch Leerzeichen sind. Leerzeichen wären tödlich, linebreaks machen - glaube ich - nichts.
nimm mal irgend eine Datei und lass mal folgende Befehlsschleife drüberlaufen.
Code:
for i in " " "\t" "\n"
do
  echo -n "Zeichen $i  : " ; cat DATEI | tr "$i" "%" | grep "%" | wc -l
done
Bei einer ganz normalen kleinen Textdatei erhalte ich folgende Ausgabe
Code:
Zeichen    : 855
Zeichen \t  : 1
Zeichen \n  : 1
Entspricht Leerzeichen, Tabs, Zeilensprünge (wobei eine 1 bei Zeilensprung bedeutet, es sind welche da, wieviel ???? ), und ist fast beliebig erweiterbar, aber bei deinen Monsterdateien bestimmt nicht schnell, aber zum testen ob die Scripte überhaupt gültige Werte bringen, reichts bestimmt. DIe Zahlen (außer Zeilensprung) bedeuten die Anzahl der Zeilen die noch solche Zeichen enthalten.
Sollten in der zu testenden Datei "%" enthalten sein, bekommst du falsche Ergebnisse. In diesem Fall müsstest du das Script auf ein anderes (nicht benutztes) Sonderzeichen ändern.

robi
 

abgdf

Guru
Hi,

hab' doch zusätzlich auch nochmal was in C gebastelt (wie immer bei C etwas mühevoll):

- Es liest immer Blöcke von (bis zu) 10MB, bevor es nach "out.tmp" schreibt.
- Es gibt Blöcke von 50 Zeichen pro Zeile aus (also keine "Schlangen").

Allerdings bin ich mir bei meinem C-Code nie ganz sicher, ob da nicht irgendwo Bugs/unerwartetes Verhalten ist, das heißt, mein C ist so eine Sache. Wäre also nett, wenn ein paar C-Kenner da nochmal drübergucken könnten (sofern gma das verwenden will):
Code:
Korrigierter C-Vorschlag s.u.
Wiederum: Benutzung auf eigene Gefahr.

Viele Grüße
 
OP
G

gma

Member
Hallo abdgf,

vielen Dank für die Bemühungen. Ich würde es gerne mal testen! Aber wie führe ich das C-program aus? Bisher gab es bei dem C-code, den ich verwendet habe, ein make file, welches das Kompilieren übernommen hat!

2. Eigene Gefahr? Was kann passieren?

gma
 
A

Anonymous

Gast
gma schrieb:
vielen Dank für die Bemühungen. Ich würde es gerne mal testen! Aber wie führe ich das C-program aus? Bisher gab es bei dem C-code, den ich verwendet habe, ein make file, welches das Kompilieren übernommen hat!
du kopierst einfach den Quellcode und legst ihn in ein temporäres Verzeichnis als Datei "cutsmall.c" ab.
dann fühst du den Befehl aus den den abgdf gleich mitgegeben hat.
Code:
gcc -Wall -Wextra -ansi -pedantic -O3 cutsmall.c -o cutsmall
und erhältst ein Programm namens "cutsmall"
dieses kannst du dann ausführen und ihm deine Datei übergeben.
Code:
./cutsmall DATEI
gma schrieb:
2. Eigene Gefahr? Was kann passieren
nicht viel, normalerweise solltest du eine Ausgabedatei "out.tmp" erhalten, in dem dein Ergebnis steht.
Allerdings hat es abgdf dann auch gleich ein bisschen zu gut gemeint ;) und ein Monster Array zusammen programmiert, das gleich so groß ist das es bei mir gleich nach dem Start des Programmes einen Speicherfehler produziert.
Segmentation fault
Das Ganze dann (auch die beiden Schleifen) mit dem Faktor 10 verkleinert und es scheint zumindestens auf dem ersten Blick funktioniert zu haben. Glaube aber es zerhackt dir auch die erste Zeile mit. Ob der Inhalt vollständig und richtig ist, kann ich so auf die Schnelle auch nicht feststellen. Bei einer Testdatei (irgend eine Logdatei) sind mir trotzdem mittendrin ein paar seltsame Zeilen aufgefallen, die irgendwie zu kurz geraten :???: :???: :???: :???: kann aber auch an der von mir probehalber vorgenommenen Verkleinerung des intern verwendeten Arrays liegen.

robi
 
OP
G

gma

Member
Das ganze dann (auch die beiden Schleifen) mit dem Faktor 10 verkleinert und es scheint zumindestens auf dem ersten Blick funktioniert zu haben. Glaube aber es zerhackt dir auch die erste Zeile mit.

Esrte Zeile ist nicht so wichtig, can ich mit cat ja wieder anhängen. Aber was meinst du mit verkleinert, bzw. beide Schleifen? Wiegesagt, ich kenne C überhaupt nicht, aber ich sehe nur eine Schleife bis 9999999 oder so?

gma

P.S.: habe gerade ein Programm gefunden, dass den Job beinahe macht, aber eben nur beinahe:
http://iubio.bio.indiana.edu/soft/molbio/readseq/java/
Leider steigt es aus, wenn ich meine ganz großen Files verwende!
 
A

Anonymous

Gast
Ich hab die beiden 9999999 zu 999999 und die eine 10000000 zu 1000000 geändert.

Java ???? ich steh mit dieser Programmiersprache ja sowieso auf Kriegsfuß und würde sie am liebsten ins Unsiversum verbannenen, aber davon mal abgesehen, wenn der Javacode nicht sauber auf eventuell vorkommende solche große Dateien abgestimmt ist, dann krachts, das ist normal.

robi
 

framp

Moderator
Teammitglied
gma schrieb:
Esrte Zeile ist nicht so wichtig, can ich mit cat ja wieder anhängen. Aber was meinst du mit verkleinert, bzw. beide Schleifen? Wiegesagt, ich kenne C überhaupt nicht, aber ich sehe nur eine Schleife bis 9999999 oder so?
Da wo 9999999 steht immer sizeof(a) reinschreiben und die 10000000 kleinermachen. Dann funktionierts.

robi schrieb:
Java ???? ich steh mit dieser Programmiersprache ja sowieso auf Kriegsfuß und würde sie am liebsten ins Unsiversum verbannenen, aber davon mal abgesehen, wenn der Javacode nicht sauber auf eventuell vorkommende solche große Dateien abgestimmt ist, dann krachts, das ist normal.
Das abstimmen auf grosse Dateien hat aber weniger mit Java zu tun sondern hängt von dem Programmierer ab :roll: . Warum stehst Du mit Java auf Kriegsfuß? Ist auch nicht die ultima ratio der ProgSprachen, aber i.d.R. die meiner Meinung nach momentan beste verfügbare Programmiersprache. (Will den Thread nicht highjacken - wir können aber gerne OT per PM darüber diskutieren ;) )
 

abgdf

Guru
Hallo,
@robi: Erstmal danke für die Erklärung des Kompilierens.
robi schrieb:
Glaube aber es zerhackt dir auch die erste Zeile mit.
Stimmt. Leider. An das Problem war ich nicht rangegangen und hatte es dann vergessen. Wenn man's nicht anders hinkriegt, müßt' ich mir halt nochmal was dazu überlegen ...
robi schrieb:
Bei einer Testdatei (irgend eine Logdatei) sind mir trotzdem mittendrin ein paar seltsame Zeilen aufgefallen, die irgendwie zu kurz geraten
Autsch. Hab' noch keine Idee dazu. Man muß sowas generell natürlich ausgiebig testen. Am besten vergleichen mit der Ausgabe der anderen Lösungen bei kleineren Dateien. Arbeit.
framp schrieb:
Da wo 9999999 steht immer sizeof(a) reinschreiben und die 10000000 kleinermachen. Dann funktionierts.
Guter Ansatz! Es sollte aber "sizeof(a) - 1" heißen:
Erklärung: Die letzte Stelle von a[] wird für das abschließende '\0' des Strings benötigt. Die Schleife soll nur höchstens bis vor dieses '\0' das Array füllen.

Das "Monsterarray" hatte ich wegen der Festplatte so groß gewählt: Je kleiner das Array ist, umso häufiger wechselt die Festplatte zwischen Lesen und Schreiben hin- und her. Aber 1MB-Größe scheint mir auch ok.

Bin nicht sicher, ob der C-Code auch auf MacOS-X kompiliert werden kann: Die Datei-IO-Funktionen sind POSIX-Funktionen, z.B. unter Windows würde das wahrscheinlich so nicht gehen (hmm, vielleicht auch doch, wer weiß ...).

@gma: Na, wie weit kommst Du mit dem C-Code? Hast Du noch Lust? So eine Neuentwicklung ist auch immer eine Frage der Geduld ...
Probier' auch mal die Python-, Perl- und sed-Sachen: Wenn Du damit hinkommst, wäre mir das eigentlich sogar lieber; C ist für mich wie gesagt immer etwas schwer zu kontrollieren.

Über Java oder nicht Java haben wir auch hier schonmal diskutiert (war da vielleicht etwas grob/provokant, fällt mir gerade auf, sehe das heute gelassener) ...

Viele Grüße

Edit: @gma: Übrigens: Was Du vielleicht auch machen könntest, wäre Deine Dateien mit "split" (man split) zu zerteilen und dann mit readseq.jar drüberzugehen. Andererseits: Wahrscheinlich wirst Du so an der split-Bruchstelle keine glatten 50er-Zeilen hinbekommen :(.
 
Oben