Kann man LibreOfficeWriter mit den letzten drei bearbeiteten Dateien per Kommando öffnen?

Ich möchte vier Starterknöpfe in der xfce4-Leiste anlegen, um LibreOffice zu öffnen, entweder

  1. wie üblich (also mit einem leeren neuen Dokument) oder
  2. mit dem letzten Dokument oder
  3. den letzten beiden Dokumenten in zwei Fenstern oder
  4. den letzten drei Dokumenten in drei Fenstern

(also pro Dokument je ein Fenster).

Ich weiß, daß man nach Is it possible to automatically open most recent document on start? LibreOffice immer mit dem zuletzt geöffneten Dokument starten kann. Das ist aber nicht, wonach ich suche, denn ich möchte lowriter auch weiter normal benutzen können.

Die im Internet (s.o.) gefundene Methode erzeugt ein Makro namens LibreOffice in der Standard Basic Bibliothek (was auch immer das ist), es verbiegt LO’s “Start Application” event auf Open_Most_Recent_Document().

Kann man das von mir gewünschte Verhalten nicht mit Kommandozeilenargumenten beim Aufruf von LibreOffice erreichen?

Man kann doch lowriter mit mehreren Dateien starten, deren Pfade im Kommando mit angegeben sind. Irgrendwo merkt sich lowriter doch, welche Dateien es zuletzte bearbeitet hat. Da müßte es doch möglich sein, notfalls über ein vorgeschaltetes Batchkommando genau diese Pfade (sicherheitshalber einzeln in doppelte Gänsefüßchen eingeschlossen, damit sie auch funktionieren, wenn in den Dateinamen Leerzeichen vorkommen) zusammen mit dem Kommando lowriter in einer Kommandozeile zu arrangieren und die dann auszuführen. Geht das? Wie geht das?

Hallo

awk -F"file:" '/name="HistoryItemRef"/{print $2}'  ~/.config/libreoffice/4/user/registrymodifications.xcu   | sed 's/<\/value><\/prop><\/node><\/item>//;s/\/\///' 

liefert in meinem Fall die zuletzt geöffneten Dateien (Dabei mag das awk und sed, das ich hier verwendet habe, nicht das Gelbe vom Ei sein).

Ein wirklich simples Skript könnte daher so aussehen, wie unten aufgeführt. Als Übergabeparameter gibt man einfach die Anzahl der Dateien an, die geöffnet werden sollen ("./ 2" hieße also die letzten beiden Dateien aus der Libreoffice History zu öffnen).

#!/bin/bash
numfiles=$1
[[ ${numfiles} == "" ]] && exit
[[ ${numfiles} -gt 3 ]] && exit

search_in_file="${HOME}/.config/libreoffice/4/user/registrymodifications.xcu"
files=$(awk -F"file:" '/name="HistoryItemRef"/{print "\""$2"\""}' ${search_in_file} \
      | sed 's/<\/value><\/prop><\/node><\/item>//;s/\/\///' \
      | head -${numfiles} | xargs )

libreoffice6.1 --writer -o ${files}

Nachtrag 10.02.2019 - Das in meinem Kommentar erwähnte sed Skript script.sed habe ich hier noch als Anhang beigefügt (Leider kann man hier keine reinen Textfiles hochladen, daher in ein .odt verpackt)

script.sed.odt


  1. LibreOffice merkt sich in registrymodifications.xcu , wie die Dateien geöffnet wurden: Wenn das per Doppelklick auf Links (z.B. auf dem Desktop) geschah, merkt es sich dort den Pfad zur Verknüpfung, nicht zu der Datei, die geöffnet werden soll. Das stört aber nicht.

  2. Leerzeichen in den Pfaden sind durch %20 ersetzt und Umlaute durch %C3%xx (mit passenden Hexadezimalzeichen xx). Vielleicht gibt es noch andere Substitutionen, um die Dateinamen mit eingeschränkten Zeichenvorrat darzustellen. Diese Substitutionen
    müßte man vor dem Gebrauch im
    awk und sed-Befehl noch rückgängig machen.

  3. Durch den awk und sed-Befehl werden die aus registrymodifications.xcu herausgezogenen Pfade zu den bearbeiteten Dateien bzw Links darauf schon richtig in doppelte Gänsefüßchen eingeschlossen. Wenn die “escapten” Zeichen ersetzt wären, würde das funktionieren.

Danke für den Startpunkt für meine weiteren Versuche.

Zu 2) Ein entsprechdes script.sed file habe ich oben in meiner ursrünglichen Antwort angehängt. Die Pipe schreibt sich dann:

awk .... | sed -f script.sed

(In diesem script.sed File werden so ziemlich alle gängigen UTF-8 Codes durch die entsprechenden Zeichen ersetzt)

Damit sollte dann auch 3) erledigt sein.

Eine Weile lang hat das bei mir mit einem Symbol auf dem Desktop funktioniert, mit dem ich LO Writer mit der zuletzt bearbeiteten Datei öffnen konnte. Leider ist mir die Lösung verlorengegangen.

Nun wollte ich aus den notierten Bestandteilen ein neues Skript bauen. Dabei schreitere ich, wenn Dateien mit Leerzeichen im Namen bearbeitet worden sind.

Der awk-Befehl

awk -F"file:" '/name="HistoryItemRef"/{print "\""$2"\""}' ${search_in_file} \
    | sed -f "/home/Skripte/UTFtoCharacter.sed"

liefert die Dateinamen aus der Historie, so daß jerder einzeln in doppelte Gänsefüßchen eingeschlossen ist: einen pro Zeile.

Mit ($(...)) drumherum kann ich das auf ein Array zugewisen - allerdings nicht pro Dateipfad, sondern an allen Leerzeichen zerstückelt. Wie vermeidet man das denn? Ich habe versucht, im print-Teil des awk-Befehls die beiden escapten \" durch escapte einfache Gänsefüßchen zu ersetzen, also \’, aber dann kommt eine Fehlermeldung

Escapesequenz »\�« wird wie ein normales »�« behandelt

und das Ergebnis ist nur der Teil vor dem ersten Leerzeichen im Pfad der zur zuletzt bearbeiteten Datei.

Wie bekommt man denn die ersten n Pfade aus der Liste, jeweils eingeschlossen in doppete Gänsdefüßchen und dann getrennt durch ein Leerzeichen statt Zeilenwechseln?

Wie schauts hiermit aus:

#!/usr/bin/env python
from lxml import etree
from pathlib import Path
from subprocess import run


config = Path.home() / ".config" / "libreoffice" / "4" / "user" / "registrymodifications.xcu"
tree = etree.parse(config)
root = tree.getroot()
namespaces = root.nsmap
history = ( "/org.openoffice.Office.Histories/"
            "Histories/"
            "org.openoffice.Office.Histories:"
            "HistoryInfo['PickList']"
            "/OrderList")

lastdocs = []
for value in tree.findall( "item/node/prop/value", namespaces=namespaces  ):
    if (node:=value.getparent().getparent()).getparent().attrib.values()[0] == history:
        number = node.attrib.values()[0]
        lastdocs.append((int(number), value.text))
        
lastdocs = [uri for _, uri in sorted(lastdocs) if uri.endswith('odt')]
docs = lastdocs[:3]
command = ['soffice']
command.extend(docs)
run(command)

Prima Idee! Ein richtiger Python-Experte bin ich nicht, aber den python-Aufruf in der ersten Zeile konnte ich so beheben und auch noch eine Sicherung gegen unter drei Einträgen in der Historie eingebaut ein paar Printausgaben eingefügt, um zu sehen, weshalb es derzeit auch nur für eine zuvor geöffnete Datei funktioniert:

#!/usr/bin/python3
# 2025-03-26

from lxml import etree
from pathlib import Path
from subprocess import run


config = Path.home() / ".config" / "libreoffice" / "4" / "user" / "registrymodifications.xcu"
tree = etree.parse(config)
root = tree.getroot()
namespaces = root.nsmap
history = ( "/org.openoffice.Office.Histories/"
            "Histories/"
            "org.openoffice.Office.Histories:"
            "HistoryInfo['PickList']"
            "/OrderList")

lastdocs = []
for value in tree.findall( "item/node/prop/value", namespaces=namespaces  ):
    if (node:=value.getparent().getparent()).getparent().attrib.values()[0] == history:
        number = node.attrib.values()[0]
        lastdocs.append((int(number), value.text))

lastdocs = [uri for _, uri in sorted(lastdocs) if uri.endswith('odt')]

# 2025-03-26 ab hier geändert...
print(f"lastdocs={lastdocs}")

anz = 3
if anz>len(lastdocs) : anz=len(lastdocs)

docs = lastdocs[:anz]           # 2025-03-26 vorher fest 3, hier auf Listenlänge begrenzt, s.o.
print(f"docs={docs}")

command = ['libreoffice25.2']   # 2025-03-26 soffice -> libreoffice25.2
command.extend(docs)
run(command)

Die aktuelle Recent-Liste enthält 7 Einträge für LO Writer, trotzdem erkennt das Skript nur einen:

a@W~$ /home/a/Skripte/öffne_LoWriter_mit_letzten_Dateien_Py.sh
lastdocs=['file:///home/a/LibreOffice.odt']
docs=['file:///home/a/LibreOffice.odt']
a@W~$

Woran liegt es, daß lastdocs nur ein Element enthält?

Keine Ahnung…bin kein Hellseher!

nimm mal den überarbeiteten code, und teste ggf. ohne die »if …endswith(‘odt’)« klausel

from lxml import etree
from pathlib import Path

def get_sorted_files():
    config = Path("../registrymodifications.xcu")
    tree = etree.parse(config)
    root = tree.getroot()
    namespaces = root.nsmap
    ooo, h = "/org.openoffice.Office", "Histories"
    tail = "HistoryInfo['PickList']/OrderList"
    attribute = ( f"{ooo}.{h}/{h}{ooo}.{h}:{tail}")
    lastdocs = []
    
    for item in tree.findall("item", namespaces):
        if item.attrib.values()[0] == attribute:
            num = int( ( node:=item.find('node') ).attrib.values()[0])
            uri = node.find('prop/value').text
            lastdocs.append((num, uri ))
    return sorted(lastdocs)
    
def main():
    _docs = get_sorted_files()
    writer_docs = [ uri for _, uri in _docs if uri.endswith('odt')]
    print(writer_docs)
main()

Zufällig hatte ich zuvor einige .doc und .docx-Dokumente offen - und die wurden ja aussortiert! Und vor kurzer Zeit habe ich mal alle recent-Listen gelöscht, weil das LO-Elephantengedächtnis etliche Megabyte groß geworden war. LO Writer kann zusätzlich auch mit .rtf-Dateien umgehen. Gibt es noch mehr Dateiformate, die im Zusammenhang mit LO Writer gängig sind und die man konsequenterweise berücksichtigen müßte?

In registrymodifications.xcu stehen z.B. auch die Pfade zu .ods-Dateien, wenn man mal mit Calc gearbeitet hat. Für Calc könnten also auch noch .csv, .tsv, .xls und .xlsx gängig sein, wenn man so was dafür auch machen wollte.

In Ihrem neuen Skript habe ich dafür gesorgt, daß

  • *.odt
  • *.doc
  • *.docx
  • *.rtf

mitgenommen werden. Ihl letztes Skript ruft aber nicht mehr libreoffice25.2 auf, sondern listet nur die sortierte Historie:

#!/usr/bin/python3

from lxml import etree
from pathlib import Path

def get_sorted_files():
    config = Path.home() / ".config/libreoffice/4/user/registrymodifications.xcu"
    tree = etree.parse(config)
    root = tree.getroot()
    namespaces = root.nsmap
    ooo, h = "/org.openoffice.Office", "Histories"
    tail = "HistoryInfo['PickList']/OrderList"
    attribute = ( f"{ooo}.{h}/{h}{ooo}.{h}:{tail}")
    lastdocs = []
    
    for item in tree.findall("item", namespaces):
        if item.attrib.values()[0] == attribute:
            num = int( ( node:=item.find('node') ).attrib.values()[0])
            uri = node.find('prop/value').text
            lastdocs.append((num, uri ))
    return sorted(lastdocs)
    
def main():
    _docs = get_sorted_files()
    writer_docs = [ uri for _
      , uri in _docs if uri.endswith('odt') or
        uri.endswith('doc') or
        uri.endswith('docx') or
        uri.endswith('rtf')
      ]
    print(writer_docs)
main()

Statt print(writer_docs) müßte man da dann, erforderlichenfalls nach Verkleinerung der Anzahl, wahrscheinlich

command = ['libreoffice25.2']   # 2025-03-26 soffice -> libreoffice25.2
command.extend(writer_docs)
run(command)

machen.

Ich habe mir das Elephantengedächtnis von LO einmal angesehen: da gibt es im Bereich

item oor:path="/org.openoffice.Office.Histories/Histories/org.openoffice.Office.Histories:HistoryInfo['PickList']/OrderList"

offenbar eine Spalte node oor:name, nach der Sie sortieren. Die zuletzt geöffneten Dokumente haben da die niedrigste Nummern. Welcher Befehl in Ihrem Code löst die Sortierung aus? In der Liste stehen die Zeilen nicht nach der Spalte sortiert! Auf 0 und 1 folgen 10, 11, 12 und dann geht es bei mir weiter mit 3, …, 9.

Wie kommt es, daß Sie in Ihrem ersten Skript die codierten Pfade so verwenden können, ohne die escapten UTF-Zeichen wieder in normale umzuwandeln ? Das scheint ja zu funktionieren.

Hallo
Können wir beim »du« bleiben? … ist eigentlich so üblich in Foren ectpp.

Offensichtlich sorted( lastdocs ) aber damit das so wie gewünscht passiert:

            # herausziehen der Nummer nebst Umwandlung zu einenem integer
            num = int( ( node:=item.find('node') ).attrib.values()[0])
            uri = node.find('prop/value').text
            # nummer und uri paarweise zur Liste hinzufügen:
            lastdocs.append((num, uri ))
            # Die Sortierung erfolgt jetzt primär nach der Nummer

ansonsten müsstest du noch die Importe ergänzen: from subprocess import run und in der »main« funktion hinzufügen:

    command = ['libreoffice25.2']   # 2025-03-26 soffice -> libreoffice25.2
    command.extend(writer_docs[:3]) # für die drei zuletzt bearbeiteten
    run(command)

Ja, anscheinend funktionieren sowohl system-pfade als auch URLs …

1 Like

Danke, karolus, für die Hilfe und die Erklärung!