Esecuzione di un file .desktop nel terminale

123

Da ciò che posso raccogliere, i file .desktop sono scorciatoie che consentono di personalizzare le impostazioni dell'applicazione. Ad esempio, ne ho molti nella mia cartella /usr/share/applications/ .

Se apro la cartella in nautilus , posso eseguire queste applicazioni semplicemente facendo doppio clic sul relativo file associato, ad es. facendo doppio clic su firefox.desktop esegue Firefox. Tuttavia, non riesco a trovare un modo per fare la stessa cosa tramite terminale.

Se faccio gnome-open foo.desktop , semplicemente apre foo.desktop come file di testo. Se lo faccio eseguibile e poi lo eseguo in bash, fallisce semplicemente (il che è previsto, non è chiaramente uno script di bash).
MODIFICA: il fare exec /fullpath/foo.desktop mi dà un messaggio Permission denied , anche se cambio la proprietà a me stesso. Se eseguo eseguibile e faccio lo stesso comando, la scheda terminale che sto usando si chiude semplicemente (suppongo che si blocchi). Infine, se faccio sudo exec /fullpath/foo.desktop , ricevo un errore che riporta sudo: exec: command not found .

Questa è la mia domanda, come posso eseguire un file foo.desktop dal terminale?

    
posta Malabarba 04.10.2010 - 15:58
fonte

16 risposte

48

Il comando eseguito è contenuto nel file desktop, preceduto da Exec= , quindi puoi estrarlo ed eseguirlo tramite:

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

Per spezzarlo

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

Potresti inserire questo in un file, diciamo ~/bin/deskopen con i contenuti

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

Quindi rendilo eseguibile

chmod +x ~/bin/deskopen

E quindi potresti fare, ad esempio

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

Gli argomenti ( %u , %F ecc.) sono dettagliati in link - nessuno di questi è rilevante per il lancio sulla riga di comando.

    
risposta data Hamish Downer 04.10.2010 - 16:52
fonte
66

La risposta dovrebbe essere

xdg-open program_name.desktop

Ma a causa di un bug questo non funziona più.

    
risposta data Richard Holloway 04.10.2010 - 17:28
fonte
62

Con qualsiasi ubuntu recente che supporti gtk-launch semplicemente vai

gtk-launch <file> dove è il nome del file .desktop senza la parte .desktop

Quindi gtk-launch foo apre foo.desktop

Se <file> non è in /usr/share/applications , /usr/local/share/applications o .local/share/applications o il luogo dove si esegue gtk-launch il comando è gtk-launch <file> <uri> . ( gtk-launch documentazione )

Utilizzabile dal terminale o alt + F2 (alt + F2 memorizza il comando nella cronologia così facilmente accessibile)

    
risposta data doug 02.12.2013 - 23:32
fonte
38

Ad oggi (12.10) il bug è ancora presente. Dipende infatti da come funziona gvfs-open (chiamato da xdg-open ).

Tuttavia, sono riuscito a risolvere il problema velocemente (rubando l'ispirazione dal codice sorgente nautilus). È un po 'complicato, ma funziona perfettamente su Ubuntu 12.10, aggiungendo un'icona significativa (non più ? ) all'avvio di Unity.

Per prima cosa, ho scritto uno script python usando Gio e l'ho salvato come ~/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)

Lo script deve avere l'autorizzazione eseguibile, quindi l'ho eseguito su un terminale:

chmod +x ~/bin/run-desktop

Poi ho creato la relativa .desktop su ~/.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

Infine ho associato la voce come gestore predefinito in ~/.local/share/applications/mimeapps.list nella sezione [Default Applications] come:

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

Ora:

  • xdg-open something.desktop funziona come previsto
  • %codice% hashbang su una voce del desktop eseguibile funziona anche

Sarà un lavoro inutile quando #!/usr/bin/xdg-open risolverà il bug, ma nel frattempo ...

    
risposta data Carlo Pellegrini 11.01.2013 - 10:06
fonte
26

Il modo giusto

Dovresti davvero usare gtk-launch se è disponibile. Di solito fa parte del pacchetto libgtk-3-bin (può variare a seconda della distribuzione).

gtk-launch viene utilizzato come segue:

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

Tieni presente che gtk-launch richiede che il file .desktop sia installato (cioè localizzato in /usr/share/applications o ~/.local/share/applications ).

Quindi, per ovviare a questo, possiamo usare una piccola funzione di Hash di Hackish che installa temporaneamente il file .desktop prima di avviarlo. Il modo "corretto" per installare un file .desktop è tramite desktop-file-install , ma ho intenzione di ignorarlo.

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

    )

}

Puoi usarlo in questo modo (e anche passare altri argomenti o URI se vuoi):

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

L'alternativa manuale

Se vuoi analizzare ed eseguire manualmente un file .desktop , puoi farlo con il seguente comando awk :

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

Se vuoi trattare il comando awk come uno script all-in-one; possiamo anche mostrare un messaggio di errore e uscire con un codice di ritorno di 1 nel caso in cui non venga trovato 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}}'

I comandi summenzionati:

  1. Trova la linea che inizia con Exec =
  2. Rimuovi Exec =
  3. Rimuovi qualsiasi variabile Exec (ad esempio %f , %u , %U ). È possibile sostituirli con argomenti posizionali come previsto dalla specifica, ma fare ciò aggiungerebbe una notevole complessità al problema. Visualizza l'ultima specifica dell'entrata del desktop .
  4. Esegui il comando
  5. Esci immediatamente con il codice di uscita appropriato (in modo da non eseguire più righe Exec )

Nota, questo script AWK risolve alcuni casi limite che potrebbero essere o non essere indirizzati correttamente da alcune delle altre risposte. In particolare, questo comando rimuove più variabili Exec (facendo attenzione a non rimuovere il simbolo%), eseguirà solo un singolo comando di riga Exec e si comporterà come previsto anche se il comando di riga Exec contiene uno o più segni di uguale (ad esempio script.py --profile=name ).

Solo alcuni altri avvertimenti ... Secondo le specifiche, TryExec è:

% Bl0ck_qu0te%

Con questo in mente, non ha senso eseguire il suo valore.

Alcune altre preoccupazioni sono Percorso e Terminale . Percorso è costituito dalla directory di lavoro per eseguire il programma in. Terminal è un valore booleano che indica se il programma viene eseguito in una finestra di terminale. Questi possono essere tutti affrontati, ma non ha senso reinventare la ruota in quanto vi sono già implementazioni delle specifiche. Se si desidera implementare Percorso , tenere presente che system() genera un sottoprocesso, quindi non è possibile modificare la directory di lavoro facendo qualcosa come system("cd 7" working_directory "7"); system(command) . Comunque potresti presumibilmente fare qualcosa come system("cd 7" working_directory "7 && " command) . Nota \ 047 sono apici singoli (quindi il comando non si interrompe sui percorsi con spazi).

L'alternativa Python

Sto rubando una pagina di Carlo qui , che ha suggerito di creare uno script Python per utilizzare gi modulo. Ecco un modo minimo per eseguire lo stesso codice dalla shell senza dover creare un file e preoccuparsi dell'I / O.

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

}

Quindi esegui la funzione di avvio come segue:

launch ./path/to/shortcut.desktop

Si noti che l'uso degli URI è facoltativo. Inoltre, non viene eseguito alcun controllo degli errori, quindi è necessario assicurarsi che il programma di avvio esista e sia leggibile (prima di utilizzarlo) se si desidera che lo script sia duraturo.

    
risposta data Six 21.08.2015 - 21:33
fonte
22

Mentre OP non stava chiedendo di KDE, per chiunque stia eseguendo KDE può essere usato il seguente comando:

kioclient exec <path-to-desktop-file>

Su Fedora, questo è incluso nel kde-runtime rpm.

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

sembra funzionare nella versione 13.10, se è installato exo-utils (come nel caso di Xubuntu).

    
risposta data jarno 22.12.2013 - 16:45
fonte
10

Potresti utilizzare dex .

dex foo.desktop
    
risposta data couac 26.01.2015 - 00:17
fonte
8

Addendum alla risposta di Hamish.

Dato lo script deskopen, puoi usare un riferimento ad esso come la riga shebang in un file .desktop , poiché il carattere del commento è ancora # . Vale a dire, metti questo come la prima riga del file .desktop :

#!/usr/bin/env deskopen

Quindi segnala il file .desktop come eseguibile (ad es. con chmod +x whatever.desktop ), quindi puoi

path/to/whatever.desktop

e voilà - L'app si aprirà! (Completa con il file dell'icona che ho specificato, anche se non ho idea di come.)

Ora, se vuoi che anche deskopen passi i parametri della riga di comando, puoi usare questa versione leggermente modificata:

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

Per inciso, ho provato a usare "#{@:2}" invece di shift ing, ma continuava a darmi 'brutta sostituzione' ...

    
risposta data pabst 09.02.2012 - 21:12
fonte
6

Al momento non esiste un'applicazione che faccia ciò che descrivi negli archivi di Ubuntu. Ci sono un paio di sforzi in corso per creare una soluzione generale per fornire l'integrazione per gli ambienti desktop (come Openbox) che non sono compatibili con queste specifiche XDG.

Arch Linux sta lavorando a un'implementazione di xdg-autostart basata sulle librerie python-xdg. Da quello che riesco a trovare, questo non sembra ancora del tutto completo, ma ha alcuni rapporti di successo.

Esiste anche un'implementazione C ++ di xdg-autostart su gitorious (http://gitorious.org/xdg-autostart/) che probabilmente beneficerebbe di un uso più ampio.

Se una delle due soluzioni funziona per te, considera di inviare il lavoro necessario per l'inclusione in Debian o Ubuntu.

Per usare uno strumento con openstart, lo chiameresti in /etc/xdg/openbox/autostart.sh (se sto leggendo correttamente la documentazione di Openbox). Se questo non funziona, puoi probabilmente chiamarlo in uno qualsiasi degli script di inizializzazione della sessione di Openbox.

    
risposta data Emmet Hikory 05.07.2011 - 07:08
fonte
6

Non ho una soluzione immediata che soddisfi i requisiti di "utilizzando un comando standard" , ma se volessi analizzare in modo minimale i file .desktop o volessi creare un alias di Bash, allora il seguente dovrebbe funzionare:

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

un altro approccio che potrebbe essere interessante, sarebbe quello di creare un metodo binfmt-misc a livello di kernel rispetto alle corrispondenze sui file .desktop (vedere grep -r . /proc/sys/fs/binfmt_misc/ per i pattern attualmente abilitati).

Alla fine della giornata, qualcosa da qualche parte dovrà analizzare i file .desktop , è solo una questione di come sia "standard / predefinito".

    
risposta data sladen 09.07.2011 - 23:22
fonte
1

Durante il tentativo di testare questi file ho trovato il modo più semplice per verificare che DM o session manager facessero quello che mi aspettavo aprisse la directory circostante in un browser di cartelle dell'interfaccia utente e quindi facevo doppio clic per aprirli.

Se ti trovi in una riga di comando: gvfs-open . o gnome-open . lo aprirà nel browser delle cartelle configurato.

La cosa sed non rispecchierà il comportamento del DM, incluse cose di poco conto come fughe e citazioni in cui davvero non vorresti un comportamento alternativo. Non è una riga di comando, ma ha convalidato le cose. Ho anche trovato l'impostazione Terminal=true utile per il debug.

    
risposta data Danny Staple 19.05.2014 - 17:20
fonte
1

Questa risposta SO è ciò che mi ha chiarito: non provare ad eseguire il file desktop, eseguire il file puntato nel file desktop.

Ad esempio, esegui /home/jsmith/Desktop/x11vnc.sh

Exec=/home/jsmith/Desktop/x11vnc.sh
    
risposta data user119824 27.06.2014 - 19:45
fonte
1

Ho preso lo script da Carlo risposta sopra, e ha tentato di migliorarlo per il mio uso desktop.

Questa versione dello script ti consentirà di eseguire qualsiasi app come se l'avessi inserita nell'HUD, purché sia probabile che sia il primo risultato. Consente inoltre di passare gli argomenti dei file per i file .desktop che non supportano gli 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)
    
risposta data Fordi 18.09.2015 - 19:20
fonte
0

Assicurati che lo script a cui punta il tuo file desktop sia anch'esso eseguibile.

Se ancora non funziona. Rendi eseguibile il file desktop nel terminale modificando Terminal=true e inseriscilo in uno script bash. Esegui lo script per rilevare l'output dell'errore. Cambia indietro quando gli errori sono corretti.

    
risposta data hakunami 26.03.2015 - 09:33
fonte
0

La risposta di Hamish è ottima, ma mi piacerebbe suggerire un'alternativa più semplice, con meno piping coinvolti:

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

In questo caso, awk cerca la riga che inizia con Exec , e poi semplicemente stampiamo i campi dopo quella linea, usando per loop e = stampiamo il campo 2, cioè qualsiasi cosa arrivi dopo quel campo. Le parentesi graffe alle estremità dei comandi, $(...) , sono sostituzioni di parametri, quindi shell eseguirà qualunque comando awk ritorni; in questo caso, restituisce il comando effettivo che viene dopo Exec= .

In alcuni rari casi potrebbe esserci più di un segno di = , che è ancora una possibilità. Per questo, ti suggerisco

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

Leggi altre domande sui tag