Datei zeilenweise durchsuchen

Du hast eine Idee für ein Projekt?
Antworten
brown78
User
Beiträge: 8
Registriert: Samstag 21. Oktober 2017, 13:43

Hallo zusammen,

ich möchte ein kleines Tool, dass mir den Ordner mit Linux *.desktop Dateien durchsucht. Die Dateien sollen dabei Zeilenweise eingelesen werden.
Ziel ist es, im Dateibrowser einen Ordner "Anwendungen" zu haben, in dem alle Anwendungen geordnet sind - ähnlich wie ein Startmenü nur im Datei Browser.
Jetzt ist es leider so, dass in den *.desktop Dateien oftmals nicht nur eine Kategorie steht. Deshalb würde ich gerne die Kategorien als Liste einlesen, diese Liste anzeigen und einen Begriff angeben. So will ich eine "Datenbank" erstellen, damit das Script bei einer neuen Datei entscheiden kann in welchen Ordner gespeichert werden soll. Ich dachte an ein Dictionary, bein dem der Key der vom User eingegebene Ordnername ist und als Value eine Liste mit den Kategorien. Dabei sollen die Values natürlich ergänzt werden können, wenn eine andere Anwendung Kategorien hat, die ich einem bereits vohandenen Ordner zuordnen will, und dabei Duplikate vermieden.

Hat die Anwendung X in den Kategorien also "System Printing Settings" stehen und ich möchte diese als System speichern, dann soll das Dictionary so ausssehen:

Code: Alles auswählen

{'System': '['Sytem", "Printing", "Settings]'}
Hat Anwendung Y in den Kategorien "System Hardware" stehen und ich möchte ebenfalls in System speichern, hätte ich das Dictionary hinterher gerne so:

Code: Alles auswählen

{'System': '["System", "Printing", "Settings", "Hardware"]'
Bisher ist mein Code so, allerdings werden so die Values überschrieben, nicht ergänzt.

Code: Alles auswählen

import os
import sys
from glob import glob

catgs = []
data = {}

for files in glob(os.path.join("/usr/share/applications/", "*.desktop")):
    with open(files) as f:
        for line in f:
            if line.startswith("Categories="):
                cat = line.strip("Categories=").split(";")
                catgs.append(cat)
                print("Kategorien: " + str(cat))
                var = input("Speichern unter: ")
                data[var] = catgs
                print(data)
                catgs = []
Ich weiß nicht ob ein Dictonary dafür geeignet ist, vielleicht hat jemand eine bessere Idee wie man sowas lösen kann.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du solltest dringend von globalen Variablen und Modul-Level Code absehen. Zerteil deinen Code in einzelnen Funktionen, die zB eine Desktop Datei behandeln und dort die Kategorien zurückliefern, und eine welche die Dateien abgrast und deine Datenbank aufbaut.

Das hilft dann oft Probleme zu erkennen.

In deinem Fall ist es die Tatsache das du die Tags immer überschreibst. Stattdessen böte sich ein defaultdict(list) an, auf dem du ein extend ausführst.
brown78
User
Beiträge: 8
Registriert: Samstag 21. Oktober 2017, 13:43

Ja das war jetzt nur meine Idee schnell hingeschrieben, um zu testen ob das überhaupt annähernd so geht.
Das wird natürlich noch in Funktionen Zerteilt.
defaultdict(list) werde ich mir genauer anschauen, so weit ging mein Kurs bisher noch nicht, sieht aber gut aus.

Was ist mit Modul-Level Code gemeint? Danke schon mal für die Antwort!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@brown78: Variablennamen sind wichtig, weil sie beim Verständnis des Programms helfen. Bei »catgs« frage ich mich, was das mit Katzen zu tun hat. »data« ist so generisch, »category_groups« wäre besser. »files« ist gar falsch, weil die Variable EINEN Dateinamen enthält.
Zeile 12: »strip« macht nicht das, was Du denkst, test das mal an »Categories=Configuration«.
Zeile 13: Du fügst einer Liste eine weitere Liste hinzu, das ist nicht das, was Du willst.
Zeile 16: hier solltest Du nicht einfach den alten Eintrag überschreiben, sondern prüfen, ob da schon ein Eintrag existiert.
Zeile 18: Statt irgendwo eine leere Liste zu definieren, die dann an anderer Stelle zu füllen um sie danach wieder zu leeren, ist sehr fehleranfällig. Wenn Du eine Liste brauchst, dann definier sie erst, wenn sie auch wirklich gebraucht wird.

Da es sich bei Desktop-Dateien um ini-Dateien handelt, solltest Du den »ConfigParser« benutzen.
brown78
User
Beiträge: 8
Registriert: Samstag 21. Oktober 2017, 13:43

Uff, ok. Bin dabei mir den Config-Parser anzusehen.... Wird wohl doch etwas aufwendiger als ich dachte...
Was tut strip denn? Also es tut nicht das was ich dachte, hab ich überprüft, aber was tut es dann?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dein gesamter Code ist Modul-Level. Das bedeutet das du Code ausführst der nicht in Funktionen gekapselt ist. Das pattern das man stattdessen nutzt ist

Code: Alles auswählen

der main():
      Tuwas()

if __name__ == '__main__': #nur wahr wenn diese Datei direkt ausgeführt wird
       main()

Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

brown78 hat geschrieben:Was tut strip denn?
Strip interpretiert den übergebenen String nicht als Pattern sondern als Menge der zu entfernenden Zeichen.
brown78
User
Beiträge: 8
Registriert: Samstag 21. Oktober 2017, 13:43

@__deets__: Danke für die Erklärung!

@kbr: Danke auch Dir für die Erläuterung, verstehen tue ich es aber nicht so ganz, denn es wird ja genau "Categories=" entfernt. Das ist das was immer am Angang der für mich relevanten Zeile steht. Wenn ich hier mehrere Zeichen dazu hänge, ändert sich auch nichts, es sei denn ich hänge genau die Zeichen an, die auch in der Zeile als nächstes kommen würden...
brown78
User
Beiträge: 8
Registriert: Samstag 21. Oktober 2017, 13:43

Momentan sieht es so aus:

Code: Alles auswählen

#!/usr/bin/env python
import os
import sys
from glob import glob
from collections import defaultdict
import pickle
     
def loadfiles():
    categories = []
    
    for file in glob(os.path.join("/usr/share/applications/", "*.desktop")):
        with open(file) as f:
            for line in f:
               if line.startswith("Categories="):
                    categories.append(line.strip("Categories=").split(";"))
    mergecategories(categories)
                  
        
def mergecategories(arg):
    categories = defaultdict(list)

    for category_list in arg:
        print("Kategorien: " + str(category_list))
        var = input("Speichern unter: ")
        categories[var].append(category_list)        
        writecategoriesdb(categories)
 

loadfiles()
Es werden nun die Kategorien jeder Datei einzeln abgefragt. Jetzt möchte ich das ganze natürlich noch abspeichern. Wie mache ich das am Besten?
Ich habe es mit Pickle schon mal probiert, dann kann ich die Datei mit Kate aber nicht mehr lesen...
Antworten