Anzeige:
Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 15 von 35

Thema: Mehrere Zeilen (unterschiedlicher Wert) aus einer Liste löschen.

  1. #1
    Registrierter Benutzer
    Registriert seit
    Sep 2015
    Beiträge
    9

    Mehrere Zeilen (unterschiedlicher Wert) aus einer Liste löschen.

    Guten Tag liebe Linux Gemeinde.

    Ich stehe vor folgendem Problem:

    Liste A (1,6 Millionen Zeilen)
    Inhalt (Abgeändert)
    AB@,AB1,AB2
    AC@,AC1,AC2
    AD@,AD1,AD2
    ...
    ...
    ...

    Liste B (60 Tausend Zeilen)
    Inhalt (Abgeändert)
    AB@
    AS@
    AL@
    ...
    ...
    ...

    Ich möchte ganz gerne das aus Liste A die Zeilen mit den Werten aus Liste B gelöscht werden.
    Meine Versuche sahen wie folgt aus (Bitte nicht den Kopf abreissen ich bin kein Experte):

    Code:
    for i in $(<ListeB); do
    
    cat ListeA | grep -v "$i" > tmp
    #cat ListeA | sed "/$i/d" > tmp
    mv tmp ListeA
    
    done
    Dadurch das beide Listen relativ groß sind habe ich natürlich total viele Schreibzugriffe und mein kleiner Code oben braucht auch extrems lange (10 Zeilen in 30-40 Sekunden)

    Kann mir jemand helfen dieses Problem Resourcen freundlicher und schneller zu lösen ?

    Vielen Dank im Vorraus.

    Gruß

  2. #2
    Registrierter Benutzer
    Registriert seit
    Dec 2003
    Ort
    Dettenhausen
    Beiträge
    22.061
    Welche Ressourcen willst Du denn schonen? Speicher oder HD-Zugrffe?

    Im Falle von (1) - sed kann das recht problemlos, im Falle von 2 z.B. Datei komplett in ein Array einlesen die Werte aus der 2. Datei rauswerfen. Oder in eine DB, ...

    Evtl. geht's auch direkt über grep, indem Du die 2. Datei als Pattern-Liste übergibst (weiß aus dem Kopf gerade nicht, wie grep da reagiert bei -v)


    edit: jepp, müsste funktionieren. grep kann's
    Geändert von marce (10.09.15 um 10:27 Uhr)
    Ich bin root - ich darf das.

  3. #3
    Registrierter Benutzer
    Registriert seit
    Sep 2015
    Beiträge
    9
    Wenn ich es mir recht überlege ist es eigentlich sinnvoller die HD-Zugriffe zu schonen.
    Gruß

  4. #4
    Registrierter Benutzer
    Registriert seit
    Sep 2015
    Beiträge
    9
    Kannst du mir bitte die Beispiele nennen ?
    Immer wenn ich mit Arrays rum spiele mache ich nur Murx :/ ..

  5. #5
    Universaldilletant Avatar von fork
    Registriert seit
    Dec 2001
    Ort
    Frankfurt/Main
    Beiträge
    1.175
    Mal ein Schuss aus der Hüfte:

    Code:
    grep -vf liste-b.txt liste-a.txt >liste-c.txt
    Evtl würde ich Liste-B so abändern, dass da nicht AB@ drin steht sondern ^AB@. Damit das Muster auch wirklich am Zeilenanfang gesucht wird.
    Geändert von fork (10.09.15 um 11:15 Uhr)

  6. #6
    Banned
    Registriert seit
    Feb 2005
    Beiträge
    1.151
    Code:
    f1=deineDatei1
    f2=deineDatei2
    
    awk 'BEGIN{ FS="," ;  i=0; printYN="Y"
                 while ( ( getline temp < "'$f2'" ) >0)
                    {array[i++]=temp}
              }
              { 
                for (i in array){
                    if ( array[i] ~ $1){
                         printYN = "N" 
                    }
                }
                if ( printYN == "Y" ) {
                     print $0
                }
                i=0
                printYN = "Y"
               }
        ' $f1
    Hier werden die Dateien nur zweimal gelesen.
    Einmal deine Datei2 im BEGIN Block, wovon jede Zeile in ein array geschrieben wird.

    Beim Lesen von Datei2 wird in einem Loop über das array nur verglichen.
    Geändert von BetterWorld (10.09.15 um 14:16 Uhr)

  7. #7
    Registrierter Benutzer
    Registriert seit
    Sep 2015
    Beiträge
    9
    Zitat Zitat von fork Beitrag anzeigen
    Mal ein Schuss aus der Hüfte:

    Code:
    grep -vf liste-b.txt liste-a.txt >liste-c.txt
    Der Befehl funktioniert natürlich, erst einmal vielen Dank dafür.
    Das Problem was hier nun besteht ist das mein Server den Prozess nach ein paar Minuten einfach killt.

  8. #8
    Registrierter Benutzer
    Registriert seit
    Sep 2015
    Beiträge
    9
    Zitat Zitat von BetterWorld Beitrag anzeigen
    Code:
    f1=deineDatei1
    f2=deineDatei2
    
    awk 'BEGIN{ FS="," ;  i=0; printYN="Y"
                 while ( ( getline temp < "'$f2'" ) >0)
                    {array[i++]=temp}
              }
              { 
                for (i in array){
                    if ( array[i] ~ $1){
                         printYN = "N" 
                    }
                }
                if ( printYN == "Y" ) {
                     print $0
                }
                i=0
                printYN = "Y"
               }
        ' $f1
    Hier werden die Dateien nur zweimal gelesen.
    Einmal deine Datei2 im BEGIN Block, wovon jede Zeile in ein array geschrieben wird.

    Beim Lesen von Datei2 wird in einem Loop über das array nur verglichen.
    Also ich habe es jetzt mit zwei Testfiles versucht aber irgendwie wird aus der Liste in der gelöscht werden soll nichts gelöscht(Ausgabe).
    Ich habe mal einfach eine DateiA mit dem Inhalt:

    ich,bin,blau
    du,bist,schlau
    wir,sind,klasse

    erstellt und eine DateiB mit dem Inhalt:

    klasse

    Die Zeile "wir,sind,klasse" wird in der Ausgabe mit ausgegeben was aber eigentlich nicht geschehen sollte da diese Zeile gelöscht werden soll bzw nicht mit ausgegeben werden soll wie es grep -v macht.
    Leider schreibt dein Script hier auch nicht das Ergebniss in eine DateiC.

    Gruß

  9. #9
    Banned
    Registriert seit
    Feb 2005
    Beiträge
    1.151
    Nun ja. Bei deinem ersten Post bezog sich in Datei 2 der Suchbegriff auf Feld #1.
    Deshalb
    Code:
    if ( array[i] ~ $1) {
    wird auch mit Feld #1 verglichen.

    Jetzt steht der Begriff aber in Feld #3. Die Zeile müsste jetzt lauten:
    Code:
    if ( array[i] ~ $3) {
    Oder, wenn es wirklich das letzte Feld ist, besser:
    Code:
    if ( array[i] ~ $NF) {

  10. #10
    Registrierter Benutzer
    Registriert seit
    Sep 2015
    Beiträge
    9
    Zitat Zitat von BetterWorld Beitrag anzeigen
    Nun ja. Bei deinem ersten Post bezog sich in Datei 2 der Suchbegriff auf Feld #1.
    Deshalb
    Code:
    if ( array[i] ~ $1) {
    wird auch mit Feld #1 verglichen.

    Jetzt steht der Begriff aber in Feld #3. Die Zeile müsste jetzt lauten:
    Code:
    if ( array[i] ~ $3) {
    Oder, wenn es wirklich das letzte Feld ist, besser:
    Code:
    if ( array[i] ~ $NF) {
    Entschuldige mein Beipiel war fehlerhaft es bezieht sich auch weiterhin auf Feld 1.
    Aber leider wird die Zeile dennoch mit ausgegeben.

    Gruß

  11. #11
    Registrierter Benutzer
    Registriert seit
    Sep 2015
    Beiträge
    9
    Zitat Zitat von BetterWorld Beitrag anzeigen
    Nun ja. Bei deinem ersten Post bezog sich in Datei 2 der Suchbegriff auf Feld #1.
    Deshalb
    Code:
    if ( array[i] ~ $1) {
    wird auch mit Feld #1 verglichen.

    Jetzt steht der Begriff aber in Feld #3. Die Zeile müsste jetzt lauten:
    Code:
    if ( array[i] ~ $3) {
    Oder, wenn es wirklich das letzte Feld ist, besser:
    Code:
    if ( array[i] ~ $NF) {
    Entschuldige mein Beipiel war fehlerhaft es bezieht sich auch weiterhin auf Feld 1.
    Aber leider wird die Zeile dennoch mit ausgegeben.

    Gruß

    Edit:

    Code:
    f1=1.txt
    f2=2.txt
    f3=3.txt
    
    awk 'BEGIN{ FS="," ;  i=0; printYN="Y"
                 while ( ( getline temp < "'$f2'" ) >0)
                    {array[i++]=temp}
              }
              { 
                for (i in array){
                    if ( array[i] ~ $1){
                         printYN = "N" 
                    }
                }
                if ( printYN == "Y" ) {
                     print $0  
                }
                i=0
                printYN = "Y"
               }
        'echo $f1 > $f3
    echo > $f1
    cat $f3 > $f1
    Dank eines Bekannten habe ich nun die Lösung die funktioniert.
    Ich bedanke mich dennoch bei allen hier und würde mich sehr über weitere Lösungsvorschläge freuen.

  12. #12
    Universaldilletant Avatar von fork
    Registriert seit
    Dec 2001
    Ort
    Frankfurt/Main
    Beiträge
    1.175
    Der Befehl funktioniert natürlich, erst einmal vielen Dank dafür.
    Das Problem was hier nun besteht ist das mein Server den Prozess nach ein paar Minuten einfach killt.
    Wie meinst Du das? Der Server killt den Prozess? Ist es nicht umgekehrt - der Prozess zieht so viel Performance, dass der Server nicht mehr erreichbar ist?

    Ich würde mal sagen, dass das schon recht performant sein dürfte. Eine erhebliche Verbesserung wird dann nochmal die Verwendung von fgrep bringen. Allerdings sind 60.000 Zeilen mit Mustern schon ein Wort. 1,6 Mio x 60.000 = ganz schön viele Lesezugriffe.

    Eine Optimierung dürfte sein, beide Dateien zu sortieren und dann immer den kleinsten Wert zu lesen.
    Mal etwas Pseudocode:

    Code:
    if key_von_datei_1.6m < key_von_datei_60k; 
        Gebe Wert aus
        lese_datei_1.6m
    else
       if key_vn_datei_1.6m > key_von_datei_60k;
          Gebe Wert aus
          lese_datei_60k
       else
            # keys sind gleich --> wert auslassen
            lese_datei_1.6m
       fi
    fi
    Anmerkung: Die AWK-Variante hat das dann zwar im Speicher, aber vergleicht immer noch 60.000 Mal für jeden Datensatz.
    Diese Variante würde insgesamt relativ wenige Vergleiche durchführen.

    Ansonsten kann man das ganze auch Beschleunigen, wenn man eine oder beide Dateien einfach nach /dev/shm (=RAM. Vorsicht: Strom weg -> Dateien weg!) kopiert und dort den fgrep ausführt - genügend Arbeitsspeicher mal vorausgesetzt.

    Btw: Kannst du mal ein paar Zahlen nennen?

    • Welche Dateigrössen haben die Dateien(MB)?
    • Wie lange dauert die derzeitige awk-Lösung?
    Geändert von fork (10.09.15 um 18:06 Uhr)

  13. #13
    Banned
    Registriert seit
    Feb 2005
    Beiträge
    1.151
    Zitat Zitat von CherryWine Beitrag anzeigen
    Entschuldige mein Beipiel war fehlerhaft es bezieht sich auch weiterhin auf Feld 1.
    Aber leider wird die Zeile dennoch mit ausgegeben.
    Code:
    ...
    ...
                i=0
                printYN = "Y"
               }
        'echo $f1 > $f3
    echo > $f1
    cat $f3 > $f1
    Dank eines Bekannten habe ich nun die Lösung die funktioniert.
    Ich bedanke mich dennoch bei allen hier und würde mich sehr über weitere Lösungsvorschläge freuen.
    Das wundert nun nicht wirklich.
    Die Zeile 'echo $f1 > $f3 ist Quark.
    Streiche das "echo" und beachte das Leerzeichen zwischen ' und $
    Die Zeile muss lauten: ' $f1 > $f3

    Witzigerweise kann ich nicht erklären, warum du da keinen Syntaxfehler erhältst. Der sollte da eigentlich kommen.

    Und das hier
    Code:
    echo > $f1
    cat $f3 > $f1
    kannst du abkürzen zu
    Code:
    cat <$f3 >$f1
    Eine Umleitung mit > löscht automatisch.
    >> würde am Ende anhängen.
    Geändert von BetterWorld (10.09.15 um 18:27 Uhr)

  14. #14
    Banned
    Registriert seit
    Feb 2005
    Beiträge
    1.151
    Zitat Zitat von fork Beitrag anzeigen
    ...Anmerkung: Die AWK-Variante hat das dann zwar im Speicher, aber vergleicht immer noch 60.000 Mal für jeden Datensatz.
    @fork Mir gefällt deine Lösung auch besser. Aber auch grep muss jeden Ausdruck auf jede Zeile anwenden.
    Da würden mich jetzt auch die Laufzeiten beider Lösungen mit den großen Dateien interessieren.

    Und wenn deine schneller ist, klaue ich dir einfach die Optimierung mit dem Sortieren. Dann is bestimmt vielleicht wieder awk schneller....

    @CherryWine einfach ein
    Code:
    time  awk ' .....
    vorangestellt gibt einen Anhaltspunkt, wie lange der Prozess wo was treibt.

  15. #15
    Registrierter Benutzer
    Registriert seit
    Dec 2003
    Ort
    Dettenhausen
    Beiträge
    22.061
    ... und wie üblich ist man nicht der Erste, der auf ein Problem stößt:
    http://stackoverflow.com/questions/4...n-another-file
    http://stackoverflow.com/questions/1...not-in-another

    passt zwar nicht 1:1, ließe sich aber jeweils recht einfach anpassen.

    Je nach Datenumfang (und 1.6Mio passt da eigentlich aus meiner Sicht rein) ist das aber eigentlich kein Job mehr für Textdateien und deren Werkzeuge sondern eher was für Datenbanken.
    Ich bin root - ich darf das.

Ähnliche Themen

  1. Wert einer Variablen an das Ende einer existierenden Datei schreiben
    Von fsanne im Forum Anwendungen Allgemein, Software
    Antworten: 4
    Letzter Beitrag: 12.02.13, 16:21
  2. SED-AWK-TR-Problem mehrere Zeilen zu einer
    Von s.fonsi im Forum Anwendungen Allgemein, Software
    Antworten: 8
    Letzter Beitrag: 29.07.08, 12:29
  3. Die ersten X Zeilen einer Datei löschen....
    Von balduin222 im Forum Linux Allgemein
    Antworten: 3
    Letzter Beitrag: 20.11.07, 13:09
  4. Antworten: 4
    Letzter Beitrag: 01.08.07, 11:10
  5. mehrere bildschirme unterschiedlicher auflösung
    Von putzw im Forum X-Konfiguration
    Antworten: 2
    Letzter Beitrag: 06.06.05, 08:19

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •