Ausführen einer .desktop-Datei im Terminal

122

Nach meinem Wissen sind .desktop -Dateien Verknüpfungen, mit denen die Einstellungen der Anwendung angepasst werden können. Ich habe zum Beispiel viele davon in meinem Ordner /usr/share/applications/ .

Wenn ich diesen Ordner in nautilus öffne, kann ich diese Anwendungen ausführen, indem Sie einfach auf die zugehörige Datei doppelklicken, z. Wenn Sie auf firefox.desktop doppelklicken, wird Firefox ausgeführt. Ich kann jedoch keinen Weg finden, das gleiche über ein Terminal zu tun.

Wenn ich gnome-open foo.desktop mache, werden einfach foo.desktop als Textdatei geöffnet. Wenn ich es ausführbar mache und dann in Bash ausführte, schlägt es einfach fehl (was erwartet wird, es ist eindeutig kein Bash-Skript).
BEARBEITEN: Wenn Sie exec /fullpath/foo.desktop ausführen, wird mir eine Nachricht von Permission denied angezeigt, auch wenn ich den Besitzer zu mir wechsle. Wenn ich ausführbar mache und denselben Befehl ausführte, wird die Registerkarte "Terminal", die ich gerade verwende, einfach geschlossen (ich denke, es stürzt ab). Wenn ich sudo exec /fullpath/foo.desktop mache, erhalte ich schließlich eine Fehlermeldung, die sudo: exec: command not found anzeigt.

Das ist meine Frage, wie kann ich eine foo.desktop -Datei vom Terminal aus ausführen?

    
Malabarba 04.10.2010, 15:58
quelle

16 Antworten

48

Der Befehl, der ausgeführt wird, befindet sich in der Desktop-Datei und wird mit Exec= vorangestellt. Sie können diesen Befehl dann extrahieren und ausführen:

'grep '^Exec' filename.desktop | tail -1 | sed 's/^Exec=//' | sed 's/%.//' | sed 's/^"//g' | sed 's/" *$//g'' &

Um das herunterzubrechen

grep  '^Exec' filename.desktop    - finds the line which starts with Exec
| tail -1                         - only use the last line, in case there are multiple
| sed 's/^Exec=//'                - removes the Exec from the start of the line
| sed 's/%.//'                    - removes any arguments - %u, %f etc
| sed 's/^"//g' | sed 's/" *$//g' - removes " around command (if present)
'...'                             - means run the result of the command run here
&                                 - at the end means run it in the background

Sie könnten dies in eine Datei schreiben, zB ~/bin/deskopen mit dem Inhalt

#!/bin/sh
'grep '^Exec' $1 | tail -1 | sed 's/^Exec=//' | sed 's/%.//' | sed 's/^"//g' | sed 's/" *$//g'' &

Dann mache es ausführbar

chmod +x ~/bin/deskopen

Und dann könnten Sie zB

tun
deskopen /usr/share/applications/ubuntu-about.desktop

Die Argumente ( %u , %F etc) werden unter link - Keine davon ist für das Starten über die Befehlszeile relevant.

    
Hamish Downer 04.10.2010, 16:52
quelle
66

Die Antwort sollte

sein
xdg-open program_name.desktop

Aufgrund eines Fehlers funktioniert dies jedoch nicht mehr.

    
Richard Holloway 04.10.2010 17:28
quelle
58

Mit jedem neuen Ubuntu, das gtk-launch unterstützt, gehen Sie einfach

gtk-launch <file> Dabei ist der Name der .desktop-Datei ohne den .desktop -Teil

gtk-launch foo öffnet also foo.desktop

Wenn <file> nicht in /usr/share/applications , /usr/local/share/applications oder .local/share/applications oder an dem Ort liegt, an dem Sie gtk-launch ausführen, lautet der Befehl gtk-launch <file> <uri> . ( gtk-launch Dokumentation )

Kann vom Terminal oder von Alt + F2 verwendet werden (Alt + F2 speichert den Befehl in der so leicht zugänglichen Historie)

    
doug 02.12.2013 23:32
quelle
38

Ab heute (12.10.) ist der Fehler weiterhin vorhanden . Es hängt in der Tat davon ab, wie gvfs-open (von xdg-open aufgerufen) funktioniert.

Trotzdem gelang es mir, eine schnelle Abhilfe zu schaffen (Inspiration aus dem Nautilus-Quellcode). Es ist ein wenig kompliziert, funktioniert aber in Ubuntu 12.10 einwandfrei und fügt ein wichtiges Symbol (nicht mehr ? ) im Unity-Launcher hinzu.

Zuerst habe ich ein Python-Skript mit Gio geschrieben und als ~/bin/run-desktop :

gespeichert
#!/usr/bin/python

from gi.repository import Gio
import sys 

def main(myname, desktop, *uris):
    launcher = Gio.DesktopAppInfo.new_from_filename(desktop)
    launcher.launch_uris(uris, None)

if __name__ == "__main__":
    main(*sys.argv)

Das Skript muss über die ausführbare Berechtigung verfügen, daher habe ich dies in einem Terminal ausgeführt:

chmod +x ~/bin/run-desktop

Dann habe ich den relativen .desktop -Eintrag auf ~/.local/share/applications/run-desktop.desktop erstellt:

[Desktop Entry]
Version=1.0
Name=run-desktop
Exec=run-desktop %U
MimeType=application/x-desktop
Terminal=false
Type=Application

Schließlich habe ich den Eintrag als Standardhandler in ~/.local/share/applications/mimeapps.list im Abschnitt [Default Applications] wie folgt zugeordnet:

[Default Applications]
....
application/x-desktop=run-desktop.desktop

Jetzt:

  • xdg-open something.desktop funktioniert wie erwartet
  • #!/usr/bin/xdg-open hashbang über einem ausführbaren Desktop-Eintrag funktioniert auch

Es wird sinnlos sein, wenn gvfs-open den Fehler beheben wird, aber in der Zwischenzeit ...

    
Carlo Pellegrini 11.01.2013 10:06
quelle
23

Der richtige Weg

Sie sollten gtk-launch wirklich verwenden, wenn es verfügbar ist. Es ist normalerweise Teil des Pakets libgtk-3-bin (dies kann je nach Distribution variieren).

gtk-launch wird wie folgt verwendet:

gtk-launch APPLICATION [URI...]
gtk-launch app-name.desktop
gtk-launch app-name

Bitte beachten Sie, dass für gtk-launch die Installation der Datei .desktop erforderlich ist (d. h. in /usr/share/applications oder ~/.local/share/applications ).

Um dies zu umgehen, können wir eine hackige kleine Bash-Funktion verwenden, die die gewünschte .desktop -Datei temporär installiert, bevor sie gestartet wird. Die "richtige" Methode, eine .desktop -Datei zu installieren, ist über desktop-file-install , aber ich werde das ignorieren.

launch(){

    # Usage: launch PATH [URI...]

    # NOTE: The bulk of this function is executed in a subshell, i.e. '(..)'
    #       This isn't strictly necessary, but it keeps everything
    #       out of the global namespace and lessens the likelihood
    #       of side effects.

    (

    # where you want to install the launcher to
    appdir=$HOME/.local/share/applications

    # the template used to install the launcher
    template=launcher-XXXXXX.desktop

    # ensure $1 has a .desktop extension, exists, is a normal file, is readable, has nonzero size
    # optionally use desktop-file-validate for stricter checking
    # desktop-file-validate "$1" 2>/dev/null || {
    [[ $1 = *.desktop && -f $1 && -r $1 && -s $1 ]] || {
        echo "ERROR: you have not supplied valid .desktop file" >&2
        return 1
    }

    # ensure the temporary launcher is deleted upon exit
    trap 'rm "$launcherfile" &>/dev/null' EXIT

    # create a temp file to overwrite later
    launcherfile=$(mktemp -p "$appdir" "$template")

    launchername=${launcherfile##*/}

    # overwrite temp file with the launcher file
    if cp "$1" "$launcherfile" &>/dev/null; then
        gtk-launch "$launchername" "${@:2}"
    else
        echo "ERROR: failed to copy launcher to applications directory" >&2
        return 1
    fi

    )

}

Sie können es wie folgt verwenden (und bei Bedarf auch zusätzliche Argumente oder URIs übergeben):

launch PATH [URI...]
launch ./path/to/shortcut.desktop

Die manuelle Alternative

Wenn Sie eine .desktop -Datei manuell analysieren und ausführen möchten, können Sie dies mit dem folgenden Befehl awk tun:

awk '/^Exec=/ {sub("^Exec=", ""); gsub(" ?%[cDdFfikmNnUuv]", ""); exit system($0)}' app-name.desktop

Wenn Sie den Befehl awk wie ein All-in-One-Skript behandeln möchten; Wir können sogar eine Fehlermeldung anzeigen und mit dem Rückkehrcode 1 beenden, falls ein Befehl Exec nicht gefunden wird:

awk 'BEGIN {command=""} /^Exec=/ {sub("^Exec=", ""); gsub(" ?%[cDdFfikmNnUuv]", ""); command=$0; exit} END {if (command!="") {exit system(command)} else {if (FILENAME == "-") {printf "ERROR: Failed to identify Exec line\n" > "/dev/stderr"} else {printf "ERROR: Failed to identify Exec line in 7%s7\n", FILENAME > "/dev/stderr"} close("/dev/stderr"); exit 1}}'

Die oben genannten Befehle werden:

  1. Suchen Sie die Zeile, die mit Exec = beginnt
  2. Entfernen Sie Exec =
  3. Entfernen Sie alle Exec-Variablen (z. B. %f , %u , %U ). Es ist möglich, diese durch Positionsargumente zu ersetzen, wie es die Spezifikation vorsieht, dies würde jedoch das Problem erheblich komplizieren. Weitere Informationen finden Sie unter Spezifikation für Desktopeinträge .
  4. Führen Sie den Befehl aus
  5. Beenden Sie sofort den entsprechenden Exit-Code (um mehrere Exec -Zeilen nicht auszuführen)

Beachten Sie, dass dieses AWK-Skript einige Randfälle behandelt, die von einigen anderen Antworten möglicherweise nicht richtig behandelt werden. Insbesondere entfernt dieser Befehl mehrere Exec -Variablen (achtet darauf, das Symbol% ansonsten nicht zu entfernen), führt nur einen einzelnen Exec -Zeilenbefehl aus und verhält sich wie erwartet auch, wenn Der Zeilenbefehl Ausführen enthält ein oder mehrere Gleichheitszeichen (z. B. script.py --profile=name ).

Nur ein paar andere Vorbehalte ... Gemäß der Spezifikation ist TryExec :

  

Pfad zu einer ausführbaren Datei auf der Festplatte, anhand der festgestellt wird, ob das Programm tatsächlich installiert ist. Wenn der Pfad kein absoluter Pfad ist, wird die Datei in der Umgebungsvariablen $ PATH gesucht. Wenn die Datei nicht vorhanden oder nicht ausführbar ist, wird der Eintrag möglicherweise ignoriert (z. B. nicht in Menüs verwendet).

Aus diesem Grund macht es keinen Sinn, den Wert auszuführen.

Einige andere Bedenken sind Pfad und Terminal . Pfad besteht aus dem Arbeitsverzeichnis, in dem das Programm ausgeführt werden soll. Terminal ist ein boolescher Wert, der angibt, ob das Programm in einem Terminalfenster ausgeführt wird. Diese können alle angesprochen werden, aber es macht keinen Sinn, das Rad neu zu erfinden, da es bereits Implementierungen der Spezifikation gibt. Wenn Sie Pfad implementieren möchten, denken Sie daran, dass system() einen Unterprozess erzeugt, sodass Sie das Arbeitsverzeichnis nicht ändern können, indem Sie system("cd 7" working_directory "7"); system(command) verwenden. Sie könnten jedoch vermutlich etwas wie system("cd 7" working_directory "7 && " command) tun. Hinweis \ 047 sind einfache Anführungszeichen (daher unterbricht der Befehl keine Pfade mit Leerzeichen).

Die Python-Alternative

Ich stehle eine Seite von Carlo hier , der vorschlug, ein Python-Skript zu erstellen, um das gi -Modul. Hier ist ein minimaler Weg, um denselben Code von der Shell aus auszuführen, ohne eine Datei erstellen zu müssen und sich um E / A kümmern zu müssen.

launch(){

# Usage: launch PATH [URI...]

python - "$@" <<EOF
import sys
from gi.repository import Gio
Gio.DesktopAppInfo.new_from_filename(sys.argv[1]).launch_uris(sys.argv[2:])
EOF

}

Führen Sie dann die Launcher-Funktion wie folgt aus:

launch ./path/to/shortcut.desktop

Beachten Sie, dass die Verwendung von URIs optional ist. Es wird auch keine Fehlerüberprüfung durchgeführt. Sie sollten also sicherstellen, dass der Launcher vorhanden und lesbar ist (bevor Sie ihn verwenden), wenn Ihr Skript dauerhaft sein soll.

    
Six 21.08.2015 21:33
quelle
21

Während OP nicht nach KDE gefragt hat, kann für jeden, der KDE ausführt, der folgende Befehl verwendet werden:

kioclient exec <path-to-desktop-file>

    
Raman 23.02.2014 19:09
quelle
10
exo-open [[path-to-a-desktop-file]...]

scheint in Version 13.10 zu funktionieren, wenn exo-utils installiert ist (wie bei Xubuntu).

    
jarno 22.12.2013 16:45
quelle
10

Sie können dex verwenden.

dex foo.desktop
    
couac 26.01.2015 00:17
quelle
8

Nachtrag zu Hamishs Antwort.

In Anbetracht des Deskopen-Skripts können Sie einen Verweis darauf als Shebang-Zeile in einer .desktop -Datei verwenden, da das Kommentarzeichen immer noch # ist. Fügen Sie dies als erste Zeile der Datei .desktop ein:

#!/usr/bin/env deskopen

Markieren Sie dann die .desktop -Datei als ausführbare Datei (z. B. mit chmod +x whatever.desktop ), und Sie können dann

path/to/whatever.desktop

und voilà - Die App wird geöffnet! (Komplett mit der von mir angegebenen Icon-Datei, obwohl ich keine Ahnung habe, wie.)

Wenn Deskopen jetzt auch Befehlszeilenparameter übergeben soll, können Sie stattdessen diese leicht modifizierte Version verwenden:

#!/bin/sh
desktop_file=$1
shift
'grep '^Exec' "${desktop_file}" | sed 's/^Exec=//' | sed 's/%.//'' "$@" &

Nebenbei habe ich versucht, "#{@:2}" anstelle von shift ing zu verwenden, aber es gab mir immer wieder "schlechte Substitution" ...

    
pabst 09.02.2012 21:12
quelle
6

Derzeit gibt es keine Anwendung, die das tut, was Sie in den Ubuntu-Archiven beschreiben. Es werden einige Anstrengungen unternommen, um eine allgemeine Lösung für die Integration von Desktop-Umgebungen (wie Openbox) zu schaffen, die diesen XDG-Spezifikationen nicht entsprechen.

Arch Linux arbeitet an einer Implementierung von xdg-autostart basierend auf den python-xdg-Bibliotheken. Nach allem, was ich finden kann, scheint dies noch nicht vollständig zu sein, es gibt jedoch einige Erfolgsberichte.

Es gibt auch eine C ++ - Implementierung von xdg-autostart für gitorious (http://gitorious.org/xdg-autostart/), die wahrscheinlich von einer umfassenderen Verwendung profitieren würde.

Wenn eine der Lösungen für Sie funktioniert, überlegen Sie, ob Sie die erforderliche Arbeit zur Aufnahme in Debian oder Ubuntu einreichen.

Um eines der beiden Tools mit openstart zu verwenden, würden Sie es in /etc/xdg/openbox/autostart.sh aufrufen (wenn ich die openbox-Dokumentation richtig lese). Wenn dies nicht funktioniert, können Sie es wahrscheinlich in einem der Openbox-Session-Initialisierungsskripts aufrufen.

    
Emmet Hikory 05.07.2011 07:08
quelle
6

Ich habe keine unmittelbare Lösung, die die Anforderung für "Verwenden eines Standardbefehls" erfüllt. Wenn Sie jedoch die .desktop -Dateien minimal parsen oder einen Bash-Alias erstellen möchten, dann sollte folgendes funktionieren:

  • awk -F= '/Exec=/{system($2); exit}' foo.desktop

Ein anderer Ansatz, der möglicherweise interessant ist, wäre das Erstellen einer binfmt-misc -Methode auf Kernelebene als die Übereinstimmung mit .desktop -Dateien (siehe grep -r . /proc/sys/fs/binfmt_misc/ für die Muster, die Sie derzeit aktiviert haben).

Am Ende des Tages muss etwas irgendwo die .desktop -Dateien analysieren, es ist nur eine Frage, wie "standard / default" das ist.

    
sladen 09.07.2011 23:22
quelle
1

Beim Versuch, diese Dateien zu testen, fand ich die einfachste Methode, um zu überprüfen, ob der DM- oder Sitzungsmanager das tun sollte, was ich erwartet hatte, das umliegende Verzeichnis in einem Ordner der Benutzeroberfläche zu öffnen und dann mit einem Doppelklick zu öffnen.

Wenn Sie sich in einer Befehlszeile befinden: gvfs-open . oder gnome-open . öffnet sie im konfigurierten Ordnerbrowser.

Das sed-Ding wird das Verhalten der DM nicht widerspiegeln, einschließlich fummeliger Sachen wie Flucht und Anführungszeichen, bei denen Sie wirklich kein alternatives Verhalten wünschen. Es ist keine Befehlszeile, aber es hat Dinge bestätigt. Ich fand auch die Einstellung Terminal=true für das Debuggen nützlich.

    
Danny Staple 19.05.2014 17:20
quelle
1

Diese SO-Antwort hat mir klar gemacht: Versuchen Sie nicht, die Desktop-Datei auszuführen, sondern die Datei, auf die in der Desktopdatei verwiesen wurde.

Führen Sie beispielsweise /home/jsmith/Desktop/x11vnc.sh

aus
Exec=/home/jsmith/Desktop/x11vnc.sh
    
user119824 27.06.2014 19:45
quelle
1

Ich habe das Skript von von Carlo's antworten , und versuchte, es für meinen eigenen Desktop zu verbessern.

Mit dieser Version des Skripts können Sie jede App so ausführen, als ob Sie sie im HUD eingegeben hätten, sofern dies wahrscheinlich das erste Ergebnis ist. Außerdem können Sie Dateiargumente für .desktop-Dateien übergeben, die keine URIs unterstützen.

#!/usr/bin/env python

from gi.repository import Gio
from argparse import ArgumentParser
import sys, os

def find_app(search_string):
    for group in Gio.DesktopAppInfo.search(search_string):
        for entry in group:
            try:
                return Gio.DesktopAppInfo.new(entry)
            except: pass
    return None

def main(args):
    launcher = None
    if os.path.isfile(args.appName):
        try:
        # If it's a file, do that first.
            launcher = Gio.DesktopAppInfo.new_from_filename(args.appName)
        except TypeError:
            print "'" + args.appName + "' is not a .desktop file"
            sys.exit(-1)
    # If it's a .desktop file in the DB, try using that
    if launcher is None and args.appName.endswith('.desktop'):
        try:
            launcher = Gio.DesktopAppInfo.new(args.appName)
        except TypeError: pass

    if launcher is None:
        # Search for the app by the text given
        launcher = find_app(args.appName)

    if launcher is None:
        print "No app named " + args.appName + " could be found"
        sys.exit(-1)
    if (launcher.supports_uris()):
        launcher.launch_uris(args.uris, None)
    elif (launcher.supports_files()):
        launcher.launch(list({ Gio.File.parse_name(x) for x in args.uris }), None)
    else :
        launcher.launch()

if __name__ == "__main__":
    argParser = ArgumentParser(description="Launch a .desktop file or application")
    argParser.add_argument("appName", 
        help="the name of any application, a desktop file's basename, or a concrete path to a desktop file", 
        action='store'
    )
    argParser.add_argument("uris", 
        nargs='*', 
        help="Files or URIs to pass to the application"
    )
    args = argParser.parse_args()
    main(args)
    
Fordi 18.09.2015 19:20
quelle
0

Stellen Sie sicher, dass das Skript, auf das Ihre Desktop-Datei verweist, auch ausführbar ist.

Wenn immer noch nicht funktioniert. Machen Sie die Desktop-Datei in Terminal lauffähig, indem Sie Terminal=true ändern und in ein Bash-Skript einfügen. Führen Sie das Skript aus, um die Fehlerausgabe abzufangen. Wechseln Sie zurück, wenn Fehler behoben wurden.

    
hakunami 26.03.2015 09:33
quelle
0

Hamishs Antwort ist großartig, aber ich würde gerne eine einfachere Alternative vorschlagen, bei der weniger Piping erforderlich ist:

$(awk -F= '/^Exec/||/^TryExec/ {print $2;exit}' /usr/share/applications/firefox.desktop)

In diesem Fall sucht awk nach einer Zeile, die mit Exec beginnt, und dann werden einfach Felder nach dieser Zeile gedruckt. Für Schleife und = drucken wir Feld 2, d. h., was nach diesem Feld kommt. Die geschweiften Klammern an den Enden der Befehle, $(...) , sind Parameterersetzungen. Daher führt die Shell die zurückgegebenen Befehle des Befehls awk aus. In diesem Fall wird der tatsächliche Befehl nach Exec= zurückgegeben.

In einigen seltenen Fällen kann es mehr als ein Zeichen = geben, was immer noch möglich ist. Dafür schlage ich vor

$(awk -F= '/^Exec/||/^TryExec/ {for(i=2;i<=NF;i++) print $i;exit}' /usr/share/applications/firefox.desktop)
    
Sergiy Kolodyazhnyy 21.08.2015 21:55
quelle