Ejecutando un archivo .desktop en la terminal

123

De lo que puedo recopilar, los archivos .desktop son accesos directos que permiten personalizar la configuración de la aplicación. Por ejemplo, tengo muchos de ellos en mi carpeta /usr/share/applications/ .

Si abro esa carpeta en nautilus , puedo ejecutar estas aplicaciones simplemente haciendo doble clic en su archivo asociado, por ejemplo. Al hacer doble clic en firefox.desktop se ejecuta Firefox. Sin embargo, no puedo encontrar una manera de hacer lo mismo a través de la terminal.

Si hago gnome-open foo.desktop , simplemente abre foo.desktop como un archivo de texto. Si lo hago ejecutable y luego lo ejecuto en bash, simplemente falla (lo que se espera, claramente no es un script de bash). EDITAR: Hacer exec /fullpath/foo.desktop me da un mensaje Permission denied , incluso si cambio de propietario a mí mismo. Si hago ejecutables y hago el mismo comando, la pestaña de terminal que estoy usando simplemente se cierra (supongo que se bloquea). Finalmente, si hago sudo exec /fullpath/foo.desktop , obtengo un error reportando sudo: exec: command not found .

Esa es mi pregunta, ¿cómo puedo ejecutar un archivo foo.desktop desde el terminal?

    
pregunta Malabarba 04.10.2010 - 15:58

16 respuestas

48

El comando que se ejecuta está contenido dentro del archivo de escritorio, precedido por Exec= para que pueda extraerlo y ejecutarlo mediante:

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

Para descomponerlo

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

Podría poner esto en un archivo, digamos ~/bin/deskopen con el contenido

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

Entonces hazlo ejecutable

chmod +x ~/bin/deskopen

Y luego podrías hacer, por ejemplo,

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

Los argumentos ( %u , %F , etc.) se detallan en enlace : ninguno de ellos es relevante para el lanzamiento en la línea de comandos.

    
respondido por el Hamish Downer 04.10.2010 - 16:52
66

La respuesta debe ser

xdg-open program_name.desktop

Pero debido a un error esto ya no funciona.

    
respondido por el Richard Holloway 04.10.2010 - 17:28
60

Con cualquier ubuntu reciente que admita gtk-launch simplemente vaya

gtk-launch <file> donde es el nombre del archivo .desktop sin la parte .desktop

Entonces gtk-launch foo abre foo.desktop

Si <file> no está en /usr/share/applications , /usr/local/share/applications o .local/share/applications o el lugar donde ejecuta gtk-launch , el comando es gtk-launch <file> <uri> . ( gtk-launch documentation )

Se puede usar desde la terminal o alt + F2 (alt + F2 almacena el comando en el historial de manera tan fácil de acceder)

    
respondido por el doug 02.12.2013 - 23:32
38

A partir de hoy (12.10) el error todavía está presente. De hecho, depende de cómo funciona gvfs-open (llamado por xdg-open ).

Aún así, logré una solución rápida (robando inspiración del código fuente de nautilus). Es un poco complicado, pero funciona perfectamente en Ubuntu 12.10, agregando un icono significativo (no más ? ) en el lanzador de Unity.

Primero, escribí una secuencia de comandos de python con Gio y la guardé como ~/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)

La secuencia de comandos debe tener el permiso ejecutable, por lo que ejecuté esto en una terminal:

chmod +x ~/bin/run-desktop

Luego creé la entrada relativa .desktop en ~/.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

Finalmente, asocié la entrada como el controlador predeterminado en ~/.local/share/applications/mimeapps.list en la sección [Default Applications] como:

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

Ahora:

  • xdg-open something.desktop funciona como se esperaba
  • %código% hashbang en la parte superior de una entrada de escritorio ejecutable también funciona

Será un trabajo inútil cuando #!/usr/bin/xdg-open resolverá el error, pero mientras tanto ...

    
respondido por el Carlo Pellegrini 11.01.2013 - 10:06
24

El camino correcto

Deberías estar usando gtk-launch si está disponible. Generalmente es parte del paquete libgtk-3-bin (esto puede variar según la distribución).

gtk-launch se utiliza de la siguiente manera:

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

Tenga en cuenta que gtk-launch requiere que se instale el archivo .desktop (es decir, ubicado en /usr/share/applications o ~/.local/share/applications ).

Por lo tanto, para solucionar esto, podemos usar una pequeña función Bash pirata que instala temporalmente el archivo deseado .desktop antes de iniciarlo. La forma "correcta" de instalar un archivo .desktop es a través de desktop-file-install pero lo ignoraré.

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

    )

}

Puede usarlo así (y también pasar argumentos adicionales o URI si lo desea):

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

La alternativa manual

Si desea analizar y ejecutar manualmente un archivo .desktop , puede hacerlo con el siguiente comando awk :

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

Si desea tratar el comando awk como un script todo en uno; incluso podemos mostrar un mensaje de error y salir con un código de retorno de 1 en el caso de que no se encuentre un comando Exec :

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}}'

Los comandos mencionados anteriormente:

  1. Busque la línea que comienza con Exec =
  2. Eliminar Exec =
  3. Eliminar cualquier variable Exec (por ejemplo, %f , %u , %U ). Es posible reemplazar estos con argumentos posicionales como pretende la especificación, pero hacerlo agregaría una complejidad significativa al problema. Consulte la última Especificación de entrada de escritorio .
  4. Ejecuta el comando
  5. Salga inmediatamente con el código de salida apropiado (para no ejecutar varias líneas Exec )

Tenga en cuenta que esta secuencia de comandos de AWK aborda algunos casos perimetrales que algunas de las otras respuestas pueden abordar de manera adecuada o no. Específicamente, este comando elimina múltiples variables Exec (teniendo cuidado de no eliminar el símbolo%), solo ejecutará un solo comando de línea Exec y se comportará como se espera, incluso si El comando de línea Exec contiene uno o más signos de igual (por ejemplo, script.py --profile=name ).

Solo algunas otras advertencias ... De acuerdo con la especificación, TryExec es:

  

Ruta a un archivo ejecutable en el disco utilizado para determinar si el programa está realmente instalado. Si la ruta no es una ruta absoluta, el archivo se busca en la variable de entorno $ PATH. Si el archivo no está presente o si no es ejecutable, la entrada puede ignorarse (no se puede usar en los menús, por ejemplo).

Teniendo esto en cuenta, no tiene sentido ejecutar su valor.

Algunas otras preocupaciones son Ruta y Terminal . Ruta consiste en el directorio de trabajo para ejecutar el programa. Terminal es un booleano que indica si el programa se ejecuta en una ventana de terminal. Todos estos pueden abordarse, pero no tiene sentido reinventar la rueda ya que ya hay implementaciones de la especificación. Si desea implementar Ruta , tenga en cuenta que system() genera un subproceso, por lo que no puede cambiar el directorio de trabajo haciendo algo como system("cd 7" working_directory "7"); system(command) . Sin embargo, presumiblemente podrías hacer algo como system("cd 7" working_directory "7 && " command) . Las notas \ 047 son comillas simples (por lo que el comando no se interrumpe en las rutas con espacios).

La alternativa de Python

Estoy robando una página de Carlo aquí , quien sugirió crear un script en Python para hacer uso de gi módulo. Aquí hay una forma mínima de ejecutar el mismo código desde el shell sin tener que crear un archivo y preocuparse por la E / S.

launch(){

# Usage: launch PATH [URI...]

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

}

Luego ejecute la función de inicio de la siguiente manera:

launch ./path/to/shortcut.desktop

Tenga en cuenta que el uso de URI es opcional. Además, no se realiza ninguna comprobación de errores, así que querrás asegurarte de que el lanzador existe y es legible (antes de usarlo) si quieres que tu script sea duradero.

    
respondido por el Six 21.08.2015 - 21:33
22

Mientras OP no preguntaba por KDE, para cualquier persona que esté ejecutando KDE se puede usar el siguiente comando:

kioclient exec <path-to-desktop-file>

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

parece funcionar en la versión 13.10, si exo-utils está instalado (como es el caso de Xubuntu).

    
respondido por el jarno 22.12.2013 - 16:45
10

Podría usar dex .

dex foo.desktop
    
respondido por el couac 26.01.2015 - 00:17
8

Anexo a la respuesta de Hamish.

Dado el script deskopen, puede usar una referencia a él como la línea shebang en un archivo .desktop , ya que el carácter de comentario todavía es # . Es decir, ponga esto como la primera línea del archivo .desktop :

#!/usr/bin/env deskopen

Luego marca el archivo .desktop como ejecutable (por ejemplo, con un chmod +x whatever.desktop ), y luego puedes

path/to/whatever.desktop

y voilà - ¡La aplicación se abrirá! (Complete con el archivo de icono que especifiqué, aunque no tengo idea de cómo hacerlo).

Ahora, si también desea que deskopen pase a través de los parámetros de la línea de comandos, puede usar esta versión ligeramente modificada:

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

Aparte de eso, traté de usar "#{@:2}" en lugar de shift ing, pero me dio una "sustitución incorrecta" ...

    
respondido por el pabst 09.02.2012 - 21:12
6

Actualmente no hay una aplicación que haga lo que usted describe en los archivos de Ubuntu. Hay un par de esfuerzos en curso para crear una solución general para proporcionar integración para entornos de escritorio (como openbox) que no cumplan con estas especificaciones XDG.

Arch Linux está trabajando en una implementación de xdg-autostart basada en las bibliotecas python-xdg. Por lo que puedo encontrar, esto parece no estar completamente completo, pero tiene algunos informes de éxito.

También hay una implementación en C ++ de xdg-autostart en gitorious (http://gitorious.org/xdg-autostart/) que probablemente se beneficiaría de un uso más amplio.

Si alguna de las soluciones funciona para usted, considere enviar el trabajo necesario para su inclusión en Debian o Ubuntu.

Para usar cualquiera de las herramientas con openstart, debería llamarlo en /etc/xdg/openbox/autostart.sh (si estoy leyendo la documentación de openbox correctamente). Si esto no funciona, probablemente pueda llamarlo en cualquiera de los scripts de inicialización de sesión de openbox.

    
respondido por el Emmet Hikory 05.07.2011 - 07:08
6

No tengo una solución inmediata que cumpla con el requisito de "usar un comando estándar" , pero si desea analizar de forma mínima los archivos .desktop o si desea crear un alias de Bash, entonces lo siguiente debería funcionar:

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

otro enfoque que podría ser interesante, sería crear un método binfmt-misc a nivel de kernel que las coincidencias en los archivos .desktop (consulte grep -r . /proc/sys/fs/binfmt_misc/ para los patrones que actualmente tiene habilitados).

Al final del día, algo en algún lugar tendrá que analizar los archivos .desktop , es solo una cuestión de cómo es "estándar / predeterminado".

    
respondido por el sladen 09.07.2011 - 23:22
1

Al intentar probar estos archivos, encontré la forma más sencilla de comprobar que el DM o el administrador de sesión haría lo que esperaba que fuera abrir el directorio circundante en un navegador de carpetas de IU y luego hacer doble clic para abrirlos.

Si está en una línea de comando: gvfs-open . o gnome-open . lo abrirá en el navegador de carpetas configurado.

Lo sedoso no reflejará el comportamiento del DM, incluyendo cosas difíciles como escapes y citas donde realmente no querrías un comportamiento alternativo. No es línea de comando, pero sí validó cosas. También encontré la configuración de Terminal=true útil para la depuración.

    
respondido por el Danny Staple 19.05.2014 - 17:20
1

Esta SO respuesta es lo que me quedó claro: no intente ejecutar el archivo de escritorio, ejecute el archivo apuntado en el archivo de escritorio.

Por ejemplo, ejecute /home/jsmith/Desktop/x11vnc.sh

Exec=/home/jsmith/Desktop/x11vnc.sh
    
respondido por el user119824 27.06.2014 - 19:45
1

Tomé el guión de Carlo's answer anterior, e intenté mejorarlo para mi uso en el escritorio.

Esta versión del script le permitirá ejecutar cualquier aplicación como si la hubiera ingresado en el HUD, siempre que sea el primer resultado. También le permite pasar argumentos de archivos para archivos .desktop que no admiten 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)
    
respondido por el Fordi 18.09.2015 - 19:20
0

Asegúrese de que el script al que apunta el archivo de su escritorio también sea ejecutable.

Si todavía no funciona. Haga que el archivo de escritorio se pueda ejecutar en el terminal cambiando Terminal=true y póngalo dentro de un script de bash. Ejecute el script para capturar la salida de error. Vuelva a cambiar cuando se corrijan los errores.

    
respondido por el hakunami 26.03.2015 - 09:33
0

La respuesta de Hamish es excelente, pero me gustaría sugerir una alternativa más simple, con menos canalizaciones involucradas:

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

En este caso, awk busca la línea que comienza con Exec , y luego simplemente imprimimos los campos después de esa línea, utilizando para bucle y = imprimimos el campo 2, es decir, lo que venga después de ese campo. Los corchetes en los extremos de los comandos, $(...) , son sustitución de parámetros, por lo que el shell ejecutará cualquier comando awk devuelto; en este caso, devuelve el comando real que viene después de Exec= .

En algunos casos raros puede haber más de un signo = , lo que todavía es una posibilidad. Para eso, te sugiero

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

Lea otras preguntas en las etiquetas