ubuntuusers.de

xml Datein löschen

Status: Gelöst | Ubuntu-Version: Server 19.04 (Disco Dingo)
Antworten |

klaus1968

Anmeldungsdatum:
20. Januar 2019

Beiträge: 6

Hallo und guten Tag @all....

vorweg: Seit etwas nachsichtig mit mir ich bin ein alter Mann , nein ich hatte vor 11 Monaten einen Schlaganfall und muss seit dem das lesen und schreiben komplett neu lernen, auch kann ich mich nicht mehr langezeit am Stück konzentrieren und kann mir auch ab und an Sachen nicht behalten ....

Jetzt aber zu meinem anderen Problem Ich habe einen Liste mit EAN-Codes (ca 250.000) ich habe ein Verzeichnis mit ca. 2,5Mio xml Datein

in den xml Datein stehen an einer Stelle der EAN Code (leider weis ich nicht wo, da in der Datei mehrer verschieden EAN stehen) wenn der EAN in dem File vorhanden ist will ich die Datei behalten alles anderen will ich nicht haben (löschen).

Kann mir jemand so ein Script oder einen Shell befehl basteln?

ich hoffe es kann mir jemand helfen.

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11261

Wohnort: München

Wenn du eine Datei datei_mit_ean_codes.txt mit einem EAN-Code pro Zeile hast, könntest du sowas machen:

1
find /pfad/zu/den/xml/dateien -type f -name "*.xml" -exec bash -c 'fgrep -f "datei_mit_ean_codes.txt" -q "$1" || rm "$1"' _ {} \;

Damit sucht find im angegeben Ordner (und seinen Unterordnern) alle Dateien mit der Endung .xml und führt für jede gefundene Datei den fgrep-Befehl aus, der die EAN-Codes aus der Datei nimmt und diese in der von find gefundenen Datei sucht. Beim ersten Treffer bricht er ab (und macht mit der nächsten gefundenen Datei weiter). Wenn es keinen Treffer gab (Exit-Code ungleich 0) löscht er die Datei.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

Vielleicht, weil ich nicht weiß, wie ein EAN-Code aussieht, kommt mir seahawk1986s Antwort etwas dünn vor.

Wie sieht denn die Liste der 250.000 EAN-Codes aus? Ein Auszug von 3-4 Zeilen wäre nett (wenn es nicht eine, Riesenzeile ist)?

Sind die Codes sortiert/geordnet?

Wie sehen diese XML-Dateien aus, 2-3 Beispiele, wenn nicht zu riesig, sonst Auszüge mit Stellen, wo der Code steht.

Bei 250.000 x 2.500.000 Vergleichen käme man mit brute force auf 625 Billionen Vergleiche - das ist auch für heutige Rechner viel Arbeit, so dass man nach Möglichkeit Liste und Dateien 1x sortiert, (Schwierigkeit: mehrere Codes in einer Datei) und dann die Dateien nach Möglichkeit alle 1x durchsucht, nicht 250.000 mal.

klaus1968

(Themenstarter)

Anmeldungsdatum:
20. Januar 2019

Beiträge: 6

seahawk1986 schrieb:

Wenn du eine Datei datei_mit_ean_codes.txt mit einem EAN-Code pro Zeile hast, könntest du sowas machen:

1
find /pfad/zu/den/xml/dateien -type f -name "*.xml" -exec bash -c 'fgrep -f "datei_mit_ean_codes.txt" -q "$1" || rm "$1"' _ {} \;

Damit sucht find im angegeben Ordner (und seinen Unterordnern) alle Dateien mit der Endung .xml und führt für jede gefundene Datei den fgrep-Befehl aus, der die EAN-Codes aus der Datei nimmt und diese in der von find gefundenen Datei sucht. Beim ersten Treffer bricht er ab (und macht mit der nächsten gefundenen Datei weiter). Wenn es keinen Treffer gab (Exit-Code ungleich 0) löscht er die Datei.

Hallo seahawk1986,

vielen dank für die Bemühung.

Leider ist im Dateiname nicht der EAN-Code enthalten, die Datei hat das Format: "20150508093538765_195.135.162.12.as2.payload_0" Also "Datum_IP-Adresse.as2.payload_0" der EAN-Code ist nur in der Datei enthalten.

klaus1968

(Themenstarter)

Anmeldungsdatum:
20. Januar 2019

Beiträge: 6

user_unknown schrieb:

Vielleicht, weil ich nicht weiß, wie ein EAN-Code aussieht, kommt mir seahawk1986s Antwort etwas dünn vor.

Wie sieht denn die Liste der 250.000 EAN-Codes aus? Ein Auszug von 3-4 Zeilen wäre nett (wenn es nicht eine, Riesenzeile ist)?

Sind die Codes sortiert/geordnet?

Wie sehen diese XML-Dateien aus, 2-3 Beispiele, wenn nicht zu riesig, sonst Auszüge mit Stellen, wo der Code steht.

Bei 250.000 x 2.500.000 Vergleichen käme man mit brute force auf 625 Billionen Vergleiche - das ist auch für heutige Rechner viel Arbeit, so dass man nach Möglichkeit Liste und Dateien 1x sortiert, (Schwierigkeit: mehrere Codes in einer Datei) und dann die Dateien nach Möglichkeit alle 1x durchsucht, nicht 250.000 mal.

Hallo user_unknown,

vielen Dank....

Ein EAN Code besteht aus 8 oder 13 Ziffern. ist auf alle Produkte bekannt als Barcode. (https://de.wikipedia.org/wiki/European_Article_Number)

Die Datei mit den 250.000 EAN sieht so aus:

4105850015559
4105250024007
4105250024335
4024984022007
4003227020109
4003227021106
4105250022003
8594403703610
7610055000509
4032315000501
7610096400108
7610096400016
4032315000617

Bevor die frage kommt wie schaut die xml Datei aus hir die ersten 50 Zeilen:

<?xml version="1.0" encoding="UTF-8"?>
<sh:StandardBusinessDocument xmlns:sh="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader"
                             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                             xsi:schemaLocation="urn:ean.ucc:2 http://www.gs1globalregistry.net/2.8/schemas/CatalogueItemNotificationProxy.xsd">
   <sh:StandardBusinessDocumentHeader>
      <sh:HeaderVersion>1.0</sh:HeaderVersion>
      <sh:Sender>
         <sh:Identifier Authority="EAN.UCC">4049111100007</sh:Identifier>
      </sh:Sender>
      <sh:Receiver>
         <sh:Identifier Authority="EAN.UCC">4399902241779</sh:Identifier>
      </sh:Receiver>
      <sh:DocumentIdentification>
         <sh:Standard>EAN.UCC</sh:Standard>
         <sh:TypeVersion>2.8</sh:TypeVersion>
         <sh:InstanceIdentifier>MSG-26c95b6d-5653-4f54-822b-4ae704d63bad</sh:InstanceIdentifier>
         <sh:Type>catalogueItemNotification</sh:Type>
         <sh:CreationDateAndTime>2015-05-08T09:15:12.008+02:00</sh:CreationDateAndTime>
      </sh:DocumentIdentification>
   </sh:StandardBusinessDocumentHeader>
   <eanucc:message xmlns:eanucc="urn:ean.ucc:2">
      <entityIdentification xsi:schemaLocation="urn:ean.ucc:2 http://www.gs1globalregistry.net/2.8/schemas/CatalogueItemNotificationProxy.xsd">
         <uniqueCreatorIdentification>MSG-26c95b6d-5653-4f54-822b-4ae704d63bad</uniqueCreatorIdentification>
         <contentOwner>
            <gln>4049111100007</gln>
         </contentOwner>
      </entityIdentification>
      <eanucc:transaction>
         <entityIdentification>
            <uniqueCreatorIdentification>TRANS-26c95b6d-5653-4f54-822b-4ae704d63bad</uniqueCreatorIdentification>
            <contentOwner>
               <gln>4002391000009</gln>
            </contentOwner>
         </entityIdentification>
         <command>
            <eanucc:documentCommand>
               <documentCommandHeader type="ADD">
                  <entityIdentification>
                     <uniqueCreatorIdentification>TRANS-26c95b6d-5653-4f54-822b-4ae704d63bad</uniqueCreatorIdentification>
                     <contentOwner>
                        <gln>4002391000009</gln>
                     </contentOwner>
                  </entityIdentification>
               </documentCommandHeader>
               <documentCommandOperand>
                  <gdsn:catalogueItemNotification xmlns:gdsn="urn:ean.ucc:gdsn:2"
                                                  creationDateTime="2015-05-08T09:15:12.008+02:00"
                                                  documentStatus="ORIGINAL"
                                                  isReload="false"
                                                  lastUpdateDate="2015-05-08">

Als es muss wirklich jede Datei geöffnet werden nach den Code gesucht werden, ist der Code vorhanden die Datei in ein Verzeichnis X kopiert werden.

Bearbeitet von ChickenLipsRfun2eat:

Codeblock spendiert!

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11261

Wohnort: München

klaus1968 schrieb:

Leider ist im Dateiname nicht der EAN-Code enthalten, die Datei hat das Format: "20150508093538765_195.135.162.12.as2.payload_0" Also "Datum_IP-Adresse.as2.payload_0" der EAN-Code ist nur in der Datei enthalten.

Das macht nichts, (f)grep durchsucht ja die Datei und interessiert sich nicht für den Dateinamen selbst (der wird nur genutzt, um die zu durchsuchenden Dateien zu öffnen). Und wenn die XML-Dateien eine andere Endung als .xml haben, muss man das im find-Befehl entsprechend anpassen.

user_unknown schrieb:

Bei 250.000 x 2.500.000 Vergleichen käme man mit brute force auf 625 Billionen Vergleiche

Das sind vermutlich noch mehr, denn es muss ja zeilenweise in jeder xml-Datei auf alle 250.000 Möglichkeiten (bzw. das was fgrep da als Ausdruck dafür baut) gematched werden, bis es einen Treffer gibt.

Natürlich gibt es da noch Raum für Optimierungen, aber dafür müsste man das Schema der XML-Dateien bzw. die Umgebung der EAN-Codes besser kennen - klaus1968 kannst du mal eine komplette xml-Datei anhängen?

Eine Idee wäre die EAN-Codes als Set zu speichern und in den XML-Datein nach 13- bzw. 8-stelligen Ziffernfolgen zu suchen und die Treffer mit dem Set zu vergleichen (wenn man die Raute in Zeile 25 entfernt, löscht er die Dateien tatsächlich):

 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
#!/usr/bin/env python3
import re
from pathlib import Path

EAN_FILE = "datei_mit_ean_codes.txt"
SEARCH_DIR = "/pfad/zu/den/xml/dateien"
FILE_GLOB = "**/*.as2.payload_0"

eans = set()
with open(EAN_FILE) as f:
    for line in f:
        eans.add(line.strip())

ean_re = re.compile(r'(\d{13}|\d{8})')
for p in Path(SEARCH_DIR).glob(FILE_GLOB):
    try:
        if not p.is_file():
            continue
        with open(p) as f:
            for line in f:
                for m in re.finditer(ean_re, line):
                    if m.group(0) in eans:
                        raise LookupError(m.group(0))
            print(f"delete file {p}")
            #p.unlink()
    except LookupError as e:
        print(f"known ean {e} in file {p}")

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

klaus1968 schrieb:

Ein EAN Code besteht aus 8 oder 13 Ziffern. ist auf alle Produkte bekannt als Barcode. (https://de.wikipedia.org/wiki/European_Article_Number)

Die Datei mit den 250.000 EAN sieht so aus:

4105850015559
4105250024007
...

Im Beispiel sieht es aus, als käme keine 8stelligen sondern nur 13stellige EANs vor - ist dem so?

Bevor die frage kommt wie schaut die xml Datei aus

Zu spät - ich habe die Frage schon gestellt. ☺

hir die ersten 50 Zeilen:

<?xml version="1.0" encoding="UTF-8"?>
...

Darin finde ich nur 13stellige EANs, in zwei Sorten von xml-Tags. Gibt es nur die 2,

1
2
<sh:Identifier Authority="EAN.UCC">4399902241779</sh:Identifier>
<gln>4049111100007</gln>

Gibt es nur die 2 oder noch mehr? Kommen vielleicht 8 oder 13stellige Ziffernfolge, eventuell auch 9 oder 14stellige und längere Nummern vor, die keine EANs sind? Das würde ich, wenn ich es nicht sicher wüsste, einmal testen.

Als es muss wirklich jede Datei geöffnet werden nach den Code gesucht werden, ist der Code vorhanden die Datei in ein Verzeichnis X kopiert werden.

Ja, die Frage ist, ob man die Dateien 250.000 mal öffnen muss bzw. - ich weiß nicht, wie fgrep da arbeitet, um 2.5 Mio. Dateien gegen so eine große Liste zu checken.

Ist das Verzeichnis mit den ca. 2,5 Mio xml-Dateien eigentlich flach, oder ist es ein Verzeichnis mit Unterverzeichnisstrukturen, die erhalten bleiben sollen?

Ich würde wohl den brute-force-Ansatz von seahawk mal 10 Minuten laufen lassen und schauen, wie weit der in 10 Minuten kommt und dann abbrechen und hochrechnen, wie lange es insgesamt dauert. Wenn das in 24h durch ist, wäre das ja wahrscheinlich akzeptabel.

Gibt es eine Schätzung, ob eher 90% oder eher 10% (fast alle/fast keine) der Dateien den Filterungsprozess überleben?

Die Beispiel-xml-Datei hat 5 EANs, 2 davon doppelt, also könnte an 3 Stellen den Filterprozess überleben. Ist das ein typischer Fall, oder sind die xml-Dateien in Realität meist viel größer und enthalten wesentlich mehr EANs?

Eine ad-hoc-Optimierungsstrategie, die mir einfiele, wäre, dass man für jede Datei die EANs einmal ausliest, und die Datei in alle Verzeichnisse kopiert, die mit den ersten X, zum Beispiel den ersten 3 Ziffern beginnt, also für die Beispieldatei:

1
2
3
4
5
6
egrep "[0-9]{8}" ean-sample.xml 
         <sh:Identifier Authority="EAN.UCC">4049111100007</sh:Identifier>
         <sh:Identifier Authority="EAN.UCC">4399902241779</sh:Identifier>
            <gln>4049111100007</gln>
               <gln>4002391000009</gln>
                        <gln>4002391000009</gln>

wären das 404, 439 und 400, bzw. sortiert 400, 404 und 439.

Die Liste mit den 250.000 Einträgen könnte man dann zerschneiden in 250 Listen mit je 1000 Einträgen im Schnitt, Gleichverteilung der Zahlenfolgen vorrausgesetzt. Womöglich ist die Verteilung der EANs aber sehr unausgewogen, was die ersten Ziffern, nicht aber was die letzten Ziffern betrifft, so dass man das Ganze lieber von hinten aufzieht, so dass man mit den Ziffern 007, 009 und 779 arbeiten würde. Ziel ist es viele etwa gleichgroße Listen zu haben.

Also käme die xml-Datei in 3 Verzeichnisse, 007, 009 und 779. Die EAN-Liste würde man mit

1
rev ean.lst | sort | rev > ean-sorted.lst

nach den letzten Ziffern sortieren. Dann würde man nach allen EANs mit der Endung 000 nur im Verzeichnis 000 suchen, dann mit denen mit der Endung 001 im Verzeichnis 001 usw. Man hätte einen großen Programmieraufwand, aber die Laufzeit wäre nur ungefähr 1/1000tel schätze ich. Ob das Programm einen Tag oder 3 Jahre läuft, das wäre den Aufwand wert, aber dafür wäre die Abschätzung gut, wie lange die Brute-Force-Methode braucht. Ob 3 Minuten oder 3000 Minuten - da würde man eher die 3000-Minutenvariante wählen, weil weniger Arbeit und weniger fehleranfällig.

Gematchte Dateien schreibt man in ein Zielverzeichnis. Wird eine Datei mehrfach ins Zielverzeichnis geschrieben ist das kein Thema.

Mit einer richtigen Programmiersprache würde ich das Problem eher so angehen: EAN-Liste sortieren. Mit grep ähnlich wie oben alle 2.5 Mio. Dateien durchfortsten, und eine Liste generieren, EAN->Dateiname(n).

1
2
4049111100007 -> sample.xml
4399902241779 -> sample.xml 

Die zweite Liste auch nach EANs sortieren. Dann kann man beide Listen in einer Schleife durchgehen. Angenommen es wäre: #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
i (hochzählen) Eanliste     XML-EAN-Filelist-Map
------------- 
...
4049111100004 4049111100004 - 
4049111100005 -             -
4049111100006 4049111100006 - 
4049111100007 -             sample.xml
4049111100008 4049111100008 - 
4049111100009 - 
...
4399902241778 - 
4399902241779 4399902241779 sample.xml
4399902241789 - 
...
5399902241779 5399902241779 a.xml b.xml u.xml 
...

Entweder es gibt ein Match, dann gibt man den/die Dateinamen aus bzw. kopiert die Datei(en) ins gute Töpfchen, oder die EAN-Liste enthält i nicht, oder es gibt keine Datei(en) die matchen.

Relativ große Vorbereitung, aber dann werden die Zahlen bis 9.999.9.... nur einmal durchlaufen.

klaus1968

(Themenstarter)

Anmeldungsdatum:
20. Januar 2019

Beiträge: 6

Also die EAN Code sind in der liste entweder 8 oder 13 Stellig (ich hab es geprüft) es gibt keinen die länger oder kürzer sind..

Im Beispiel sieht es aus, als käme keine 8stelligen sondern nur 13stellige EANs vor - ist dem so?

Nein es gibt auch 8 Stellige die sind weiter oben ☺

Darin finde ich nur 13stellige EANs, in zwei Sorten von xml-Tags. Gibt es nur die 2,

es gibt auch Datein mit 8 Stelligen EAN leider ist es mir nicht möglich hier Datein hoch zu laden und dann wäre es wirklicher zufall wenn ich einen mit 8 Stellen erwischen würde.

Gibt es nur die 2 oder noch mehr? Kommen vielleicht 8 oder 13stellige Ziffernfolge, eventuell auch 9 oder 14stellige und längere Nummern vor, die keine EANs sind? Das würde ich, wenn ich es nicht sicher wüsste, einmal testen.

Du es kann wirklich vorkommen das in den XML Datein auch welche mit mehr oder weniger Zahlen kommen kann, die sind aber nicht gültig und könnten gelöscht werden.

Sorry ich muss später den rest beantworten .... *kopfrauch*

klaus1968

(Themenstarter)

Anmeldungsdatum:
20. Januar 2019

Beiträge: 6

Hallo seahawk1986,

vielen dank für die Hilfe du hast mir ein Stein vom Herzen genommen.

klaus1968

(Themenstarter)

Anmeldungsdatum:
20. Januar 2019

Beiträge: 6

weil es ggf den einen oder anderen interessiert.

in 60 Sekunden schaft das Script 11.484 Files zu löschen. (Auf einer SSD HDD)

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

klaus1968 schrieb:

weil es ggf den einen oder anderen interessiert.

in 60 Sekunden schaft das Script 11.484 Files zu löschen. (Auf einer SSD HDD)

Das wären dann in einer Stunde ca. 600.000 und in 4h wären die ca. 2.5 Mio. durch. Dann würde ich das so nehmen.

Antworten |