web-dev-qa-db-fra.com

Exécuter un fichier .desktop dans le terminal

D'après ce que je peux comprendre, les fichiers .desktop sont des raccourcis permettant de personnaliser les paramètres de l'application. Par exemple, j'en ai beaucoup dans mon dossier /usr/share/applications/.

Si j'ouvre ce dossier dans nautilus, je peux exécuter ces applications en double-cliquant sur le fichier qui lui est associé, par exemple. en double-cliquant sur firefox.desktop exécute Firefox. Cependant, je ne trouve pas le moyen de faire la même chose via un terminal.

Si je fais gnome-open foo.desktop, il ouvre simplement foo.desktop sous forme de fichier texte. Si je le rends exécutable puis que je l'exécute en bash, il échoue simplement (ce qui est attendu, ce n'est clairement pas le script bash).
EDIT: Faire exec /fullpath/foo.desktop me donne un message Permission denied, même si je change de propriétaire pour moi-même. Si je m’exécute et que je fais la même commande, l’onglet du terminal que j’utilise est tout simplement fermé (je suppose qu’il se bloque). Enfin, si je fais Sudo exec /fullpath/foo.desktop, je reçois une erreur en signalant Sudo: exec: command not found.

Telle est ma question, comment puis-je exécuter un fichier foo.desktop à partir du terminal?

137
Malabarba

La commande qui est exécutée est contenue dans le fichier du bureau, précédée de Exec= afin que vous puissiez l'extraire et l'exécuter comme suit:

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

Pour décomposer cela

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

Vous pouvez mettre ceci dans un fichier, disons ~/bin/deskopen avec le contenu

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

Puis le rendre exécutable

chmod +x ~/bin/deskopen

Et alors vous pourriez faire, par exemple

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

Les arguments (%u, %F etc) sont détaillés dans http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html#exec-variables - aucun des ils sont pertinents pour le lancement en ligne de commande.

52
Hamish Downer

La réponse devrait être

xdg-open program_name.desktop

Mais à cause de n bug cela ne fonctionne plus.

82
Richard Holloway

Avec n'importe quel ubuntu récent qui supporte gtk-launch, allez simplement

gtk-launch <file> où est le nom du fichier .desktop sans la partie .desktop

Donc gtk-launch foo ouvre foo.desktop

( gtk-launch documentation )

Le fichier .desktop doit se trouver dans/usr/share/applications,/usr/local/share/applications ou ~/.local/share/applications (- vous pouvez apparemment utiliser .desktop si vous le souhaitez.

Utilisable depuis le terminal ou alt + F2 (alt + F2 enregistre la commande dans l'historique si facilement accessible)

68
doug

A partir d'aujourd'hui (12h10) le bogue est toujours présent. Cela dépend en fait du fonctionnement de gvfs-open (appelé par xdg-open).

Malgré tout, j’ai réussi à contourner rapidement le problème (en m'inspirant du code source de Nautilus). C'est un peu compliqué, mais fonctionne parfaitement sur Ubuntu 12.10, en ajoutant une icône significative (pas plus de ?) sur le lanceur Unity.

Tout d'abord, j'ai écrit un script python à l'aide de Gio et l'ai placé sous le nom ~/bin/run-desktop:

#!/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 __== "__main__":
    main(*sys.argv)

Le script doit avoir l'autorisation de l'exécutable, j'ai donc lancé ceci dans un terminal:

chmod +x ~/bin/run-desktop

Ensuite, j'ai créé l'entrée relative .desktop sur ~/.local/share/applications/run-desktop.desktop:

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

Enfin, j'ai associé l'entrée en tant que gestionnaire par défaut dans ~/.local/share/applications/mimeapps.list sous la section [Default Applications] comme suit:

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

À présent:

  • xdg-open quelque chose.desktop fonctionne comme prévu
  • #!/usr/bin/xdg-open hashbang au-dessus d'une entrée de bureau exécutable fonctionne aussi

Ce sera un travail inutile lorsque gvfs-open résoudra le bogue, mais entre-temps ...

38
Carlo Pellegrini

Le droit chemin

Vous devriez vraiment utiliser gtk-launch s'il est disponible. Cela fait généralement partie du paquet libgtk-3-bin (cela peut varier en fonction de la distribution).

gtk-launch est utilisé comme suit:

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

Veuillez noter que gtk-launch nécessite l’installation du fichier . Desktop (c’est-à-dire situé dans /usr/share/applications ou ~/.local/share/applications).

Donc, pour contourner ce problème, nous pouvons utiliser une petite fonction haletante de Bash qui installe temporairement le fichier souhaité . Desktop avant de le lancer. Le "bon" moyen d'installer un fichier . Desktop est via desktop-file-install mais je vais l'ignorer.

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

    )

}

Vous pouvez l'utiliser comme ça (et également transmettre des arguments supplémentaires ou des URI si vous le souhaitez):

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

L'alternative manuelle

Si vous souhaitez analyser et exécuter manuellement un fichier . Desktop, vous pouvez le faire à l'aide de la commande awk suivante:

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

Si vous souhaitez traiter la commande awk comme un script tout-en-un; nous pouvons même afficher un message d'erreur et quitter avec un code de retour de 1 dans le cas où une commande Exec n'est pas trouvée:

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 \047%s\047\n", FILENAME > "/dev/stderr"} close("/dev/stderr"); exit 1}}'

Les commandes susmentionnées vont:

  1. Trouvez la ligne commençant par Exec =
  2. Supprimer Exec =
  3. Supprimez toutes les variables Exec (par exemple, %f, %u, %U). Il est possible de remplacer ceux-ci par des arguments de position comme le prévoit la spécification, mais cela compliquerait considérablement le problème. Voir les dernières Spécification d'entrée sur le burea .
  4. Exécuter la commande
  5. Quitter immédiatement avec le code de sortie approprié (pour ne pas exécuter plusieurs lignes Exec)

Remarque: ce script AWK aborde quelques cas Edge qui peuvent ou ne peuvent pas être traités correctement par certaines des autres réponses. Plus précisément, cette commande supprime plusieurs variables Exec (en prenant soin de ne pas supprimer le symbole%), n'exécutera qu'une seule commande Exec line et se comportera comme prévu, même si la ligne Exec line contient un ou plusieurs signes d’égalité (par exemple, script.py --profile=name).

Juste quelques autres avertissements ... Selon la spécification, TryExec est:

Chemin d'accès à un fichier exécutable sur le disque utilisé pour déterminer si le programme est réellement installé. Si le chemin n'est pas un chemin absolu, le fichier est recherché dans la variable d'environnement $ PATH. Si le fichier n'est pas présent ou s'il n'est pas exécutable, l'entrée peut être ignorée (ne pas être utilisée dans les menus, par exemple).

Dans cet esprit, il n’a aucun sens d’exécuter sa valeur.

Quelques autres préoccupations sont Path et Terminal. Path comprend le répertoire de travail dans lequel exécuter le programme. Terminal est un booléen indiquant si le programme est exécuté dans une fenêtre de terminal. Tous ces problèmes peuvent être résolus, mais il est inutile de réinventer la roue car il existe déjà des implémentations de la spécification. Si vous souhaitez implémenter Path, gardez à l'esprit que system() génère un sous-processus, vous ne pouvez donc pas modifier le répertoire de travail en effectuant quelque chose comme system("cd \047" working_directory "\047"); system(command). Cependant, vous pourriez probablement faire quelque chose comme system("cd \047" working_directory "\047 && " command). Note\047 sont des guillemets simples (pour que la commande ne soit pas interrompue sur les chemins contenant des espaces).

La Python Alternative

Je vole une page de Carlo ici , qui a suggéré de créer un script Python pour utiliser le module gi. Voici un moyen minimal d'exécuter le même code à partir du shell sans avoir à créer un fichier et à vous préoccuper des entrées/sorties.

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

}

Puis exécutez la fonction lanceur comme suit:

launch ./path/to/shortcut.desktop

Notez que l'utilisation des URI est facultative. En outre, aucune vérification d'erreur n'est effectuée. Vous devez donc vous assurer que le programme de lancement existe et qu'il est lisible (avant de l'utiliser) si vous souhaitez que votre script soit durable.

30
Six

Même si OP ne posait pas de questions sur KDE, vous pouvez utiliser la commande suivante pour tous ceux qui l'exécutent:

kioclient exec <path-to-desktop-file>

Sur Fedora, cela est inclus dans le __pm code kde-runtime.

26
Raman

Vous pouvez utiliser dex .

dex foo.desktop
13
couac
exo-open [[path-to-a-desktop-file]...]

semble fonctionner dans la version 13.10, si exo-utils est installé (comme c'est le cas avec Xubuntu).

13
jarno

Addendum à la réponse de Hamish.

Étant donné le script deskopen, vous pouvez utiliser une référence à celle-ci en tant que ligne Shebang dans un fichier . Desktop, car le caractère de commentaire est toujours #. C'est-à-dire, mettez ceci comme première ligne du fichier . Desktop:

#!/usr/bin/env deskopen

Marquez ensuite le fichier . Desktop en tant que fichier exécutable (par exemple avec un chmod +x whatever.desktop), puis vous pourrez

path/to/whatever.desktop

et voilà - L'application va s'ouvrir! (Complétez le fichier d'icône que j'ai spécifié, bien que je ne sache pas comment.)

Maintenant, si vous souhaitez également que deskopen transmette des paramètres de ligne de commande, vous pouvez utiliser cette version légèrement modifiée:

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

En passant, j'ai essayé d'utiliser "#{@:2}" au lieu de shifting, mais cela continuait à me donner une "mauvaise substitution" ...

8
pabst

Il n'y a actuellement aucune application qui réponde à vos besoins dans les archives Ubuntu. Quelques efforts sont en cours pour créer une solution générale offrant une intégration pour les environnements de bureau (tels que openbox) qui ne sont pas conformes à ces spécifications XDG.

Arch Linux travaille sur une implémentation de xdg-autostart basée sur les bibliothèques python-xdg. D'après ce que je peux trouver, cela ne semble pas encore tout à fait complet, mais il existe des rapports de succès.

Il existe également une implémentation C++ de xdg-autostart sur gitorious (http://gitorious.org/fr/xdg-autostart/) qui bénéficierait probablement d'une utilisation plus large.

Si l'une de ces solutions vous convient, envisagez de soumettre le travail nécessaire à l'inclusion dans Debian ou Ubuntu.

Pour utiliser l’un ou l’autre des outils avec openstart, vous devez l’appeler dans /etc/xdg/openbox/autostart.sh (si je lis correctement la documentation openbox). Si cela ne fonctionne pas, vous pouvez probablement l'appeler dans n'importe lequel des scripts d'initialisation de session openbox.

6
Emmet Hikory

Je n'ai pas de solution immédiate répondant à l'exigence de "à l'aide d'une commande standard", mais si vous souhaitez analyser de manière minimale les fichiers .desktop ou si vous souhaitez créer un alias Bash, les opérations suivantes devraient fonctionner :

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

une autre approche, qui pourrait être intéressante, consisterait à créer une méthode binfmt-misc au niveau du noyau, qui correspond aux fichiers .desktop (voir grep -r . /proc/sys/fs/binfmt_misc/ pour les modèles que vous avez activés).

À la fin de la journée, quelque chose devra analyser quelque part les fichiers .desktop, il s’agit simplement de savoir comment "standard/par défaut".

6
sladen

J'ai pris le script de Carloréponse ci-dessus et j'ai tenté de l'améliorer pour mon propre usage sur le bureau.

Cette version du script vous permettra d'exécuter n'importe quelle application comme si vous l'aviez entrée sur le HUD, à condition que ce soit probablement le premier résultat. Il vous permet également de passer des arguments de fichier pour les fichiers .desktop qui ne prennent pas en charge les URI.

#!/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 __== "__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)
1
Fordi

(Compilé à partir des différentes autres réponses ici)

En fonction de votre système et des divers bogues qui peuvent ou non exister sur votre système, essayez les étapes suivantes jusqu'à ce que l'un d'entre eux fonctionne:

  1. xdg-open program_name.desktop
  2. exo-open program_name.desktop
  3. gtk-launch program_name.desktop
  4. kioclient exec program_name.desktop
  5. dex program_name.desktop

Notez que sur les systèmes Ubuntu, vos lanceurs de bureau "Menu Démarrer" sont disponibles dans /usr/share/applications/.

À titre d'exemple, pour montrer quelles commandes ci-dessus fonctionnent ou non sur mon système Ubuntu 14.04, voici les résultats des appels suivants pour moi:

  1. xdg-open /usr/share/applications/Eclipse_for_cpp.desktop # Echoue à cause d'un bogue (essaie de me faire sauvegarder ce fichier .desktop)
  2. exo-open /usr/share/applications/Eclipse_for_cpp.desktop # Works
  3. gtk-launch /usr/share/applications/Eclipse_for_cpp.desktop # échoue avec "gtk-launch: aucune application de ce type"
  4. kioclient exec /usr/share/applications/Eclipse_for_cpp.desktop # Works
  5. dex /usr/share/applications/Eclipse_for_cpp.desktop # échoue, & Sudo apt install dex ne peut pas localiser le paquet dex
1
Gabriel Staples

En essayant de tester ces fichiers, j'ai trouvé le moyen le plus simple de vérifier que le DM ou le gestionnaire de session ferait ce que je pensais être d'ouvrir le répertoire environnant dans un navigateur de dossier d'interface utilisateur, puis de double-cliquer dessus pour l'ouvrir. .

Si vous êtes en ligne de commande: gvfs-open . ou gnome-open . l'ouvrira dans le navigateur de dossiers configuré.

Le système sed ne reflétera pas le comportement du sous-ministre, y compris des choses délicates telles que des évasions et citant les endroits où vous ne voudriez vraiment pas avoir un comportement alternatif. Ce n'est pas une ligne de commande, mais cela a validé les choses. J'ai également trouvé utile de configurer Terminal=true pour le débogage.

1
Danny Staple

Ceci SO réponse est ce qui m’a clairement expliqué: n’essayez pas d’exécuter le fichier de bureau, mais exécutez le fichier indiqué dans le fichier de bureau.

Par exemple, exécutez /home/jsmith/Desktop/x11vnc.sh

Exec=/home/jsmith/Desktop/x11vnc.sh
1
user119824

Assurez-vous que le script sur lequel pointe votre fichier de bureau est également exécutable.

Si ça ne marche toujours pas. Rendre le fichier de bureau exécutable dans le terminal en changeant Terminal=true et le placer dans un script bash. Exécutez le script pour intercepter la sortie d'erreur. Revenir en arrière lorsque les erreurs sont corrigées.

0
hakunami

La réponse de Hamish est excellente, mais j'aimerais suggérer une alternative plus simple, avec moins de tuyauterie:

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

Dans ce cas, awk recherche une ligne commençant par Exec, puis nous imprimons simplement les champs après cette ligne. En utilisant for et =, nous imprimons le champ 2, c’est-à-dire tout ce qui suit ce champ. Les accolades aux extrémités des commandes, $(...), sont des substitutions de paramètres. Shell exécutera donc toutes les commandes awk renvoyées; dans ce cas, il retourne la commande réelle qui vient après Exec=.

Dans de rares cas, il peut y avoir plus d'un signe =, ce qui est toujours une possibilité. Pour cela, je suggère

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