Exécution d'un fichier .desktop dans le terminal

123

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. Un double-clic 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 rend 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 .

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

    
posée Malabarba 04.10.2010 - 15:58
la source

16 réponses

48

La commande 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 avec:

'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 placer ceci dans un fichier, par exemple ~/bin/deskopen avec le contenu

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

Ensuite, rendez-le 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 link - aucun d’entre eux n’est pertinent pour un lancement en ligne de commande.

    
réponse donnée Hamish Downer 04.10.2010 - 16:52
la source
66

La réponse devrait être

xdg-open program_name.desktop

Mais en raison de un bogue , cela ne fonctionne plus.

    
réponse donnée Richard Holloway 04.10.2010 - 17:28
la source
62

Avec tout ubuntu récent qui prend en charge gtk-launch , allez simplement

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

So gtk-launch foo ouvre foo.desktop

Si <file> n'est pas dans /usr/share/applications , /usr/local/share/applications ou .local/share/applications ou à l'endroit où vous exécutez gtk-launch , la commande est gtk-launch <file> <uri> . ( gtk-launch documentation )

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

    
réponse donnée doug 02.12.2013 - 23:32
la source
38

À compter 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 à trouver une solution rapide (en me inspirant du code source de Nautilus). Il 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 de ~/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 __name__ == "__main__":
    main(*sys.argv)

Le script doit disposer de l'autorisation exécutable. J'ai donc exécuté 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] en tant que:

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

Maintenant:

  • 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 ...

    
réponse donnée Carlo Pellegrini 11.01.2013 - 10:06
la source
26

La bonne façon

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 requiert 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 hacheuse Bash qui installe temporairement le fichier .desktop souhaité avant de le lancer. La méthode "correcte" pour 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 transmettre si vous le souhaitez des arguments supplémentaires ou des URI):

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

Les commandes susmentionnées vont:

  1. Recherchez 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. Consultez la dernière spécification d'entrée de bureau .
  4. Exécuter la commande
  5. Quittez immédiatement avec le code de sortie approprié (pour ne pas exécuter plusieurs lignes Exec )

Remarque: ce script AWK traite quelques cas marginaux qui peuvent ou non ê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 de ligne Exec et se comportera comme prévu, même si la commande de ligne Exec contient un ou plusieurs signes d’égal (par exemple, script.py --profile=name ).

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

Path to an executable file on disk used to determine if the program is actually installed. If the path is not an absolute path, the file is looked up in the $PATH environment variable. If the file is not present or if it is not executable, the entry may be ignored (not be used in menus, for example).

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

Path et Terminal sont quelques autres problèmes. Chemin comprend le répertoire de travail dans lequel le programme est exécuté. Terminal est un booléen indiquant si le programme est exécuté dans une fenêtre de terminal. Tout cela peut être résolu, 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. Par conséquent, vous ne pouvez pas modifier le répertoire de travail en effectuant une opération telle que system("cd 7" working_directory "7"); system(command) . Cependant, vous pourriez probablement faire quelque chose comme system("cd 7" working_directory "7 && " command) . Note \ 047 sont des guillemets simples (pour que la commande ne soit pas interrompue sur les chemins contenant des espaces).

L'alternative Python

Je vole une page de Carlo, ici , qui a suggéré de créer un script Python pour utiliser le gi . Voici un moyen minimal d’exécuter le même code à partir du shell sans avoir à créer un fichier et à vous soucier 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

}

Exécutez ensuite la fonction de lancement comme suit:

launch ./path/to/shortcut.desktop

Notez que l'utilisation des URI est facultative. De plus, 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 voulez que votre script soit durable.

    
réponse donnée Six 21.08.2015 - 21:33
la source
22

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 kde-runtime rpm.

    
réponse donnée Raman 23.02.2014 - 19:09
la source
10
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).

    
réponse donnée jarno 22.12.2013 - 16:45
la source
10

Vous pouvez utiliser dex .

dex foo.desktop
    
réponse donnée couac 26.01.2015 - 00:17
la source
8

Addendum à la réponse de Hamish.

Etant 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, placez-le comme première ligne du fichier .desktop :

#!/usr/bin/env deskopen

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

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 les 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 shift ing, mais cela continuait à me donner une "mauvaise substitution" ...

    
réponse donnée pabst 09.02.2012 - 21:12
la source
6

Il n'y a actuellement aucune application qui fasse ce que vous décrivez 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 (comme openbox) non 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 quelques succès ont été rapportés.

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

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 l'un des scripts d'initialisation de session openbox.

    
réponse donnée Emmet Hikory 05.07.2011 - 07:08
la source
6

Je n'ai pas de solution immédiate répondant à la condition requise pour "utiliser une commande standard" , mais si vous souhaitez analyser au minimum les fichiers .desktop ou créer un alias Bash, alors ce qui suit devrait fonctionner:

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

Une autre approche intéressante pourrait être de 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 quelque part analyser les fichiers .desktop , il s’agit simplement de savoir comment cela est "standard / par défaut".

    
réponse donnée sladen 09.07.2011 - 23:22
la source
1

En essayant de tester ces fichiers, j’ai trouvé le moyen le plus simple de vérifier que le gestionnaire de session ou le gestionnaire de sessions ferait ce que j’attendais: ouvrir le répertoire environnant dans un navigateur de dossiers d’UI, puis double-cliquer dessus pour les ouvrir.

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

La solution 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 pas d'un comportement alternatif. Ce n'est pas une ligne de commande, mais cela a validé les choses. J'ai aussi trouvé le paramètre Terminal=true utile pour le débogage.

    
réponse donnée Danny Staple 19.05.2014 - 17:20
la source
1

Cette réponse SO SO est ce qui m’a bien expliqué: ne tentez pas d’exécuter le fichier du bureau, exécutez la fichier pointé dans le fichier du bureau.

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

Exec=/home/jsmith/Desktop/x11vnc.sh
    
réponse donnée user119824 27.06.2014 - 19:45
la source
1

J'ai pris le script de Carlo's répondre ci-dessus et a 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 __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)
    
réponse donnée Fordi 18.09.2015 - 19:20
la source
0

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

Si cela ne fonctionne toujours pas. Rendez le fichier desktop exécutable dans le terminal en changeant Terminal=true et insérez-le dans un script bash. Exécutez le script pour intercepter la sortie d'erreur. Remettre en place lorsque les erreurs sont corrigées.

    
réponse donnée hakunami 26.03.2015 - 09:33
la source
0

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 cherche une ligne commençant par Exec , puis nous imprimons simplement les champs après cette ligne, en utilisant for 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. Par conséquent, le shell exécutera 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)
    
réponse donnée Sergiy Kolodyazhnyy 21.08.2015 - 21:55
la source

Lire d'autres questions sur les étiquettes