Il modo giusto
Dovresti davvero usare gtk-launch
se è disponibile. Di solito fa parte del pacchetto libgtk-3-bin (questo può variare in base alla distribuzione).
gtk-launch
è usato come segue:
gtk-launch APPLICATION [URI...]
gtk-launch app-name.desktop
gtk-launch app-name
Si noti che gtk-launch
richiede l' installazione del file .desktop (ovvero situato in /usr/share/applications
o ~/.local/share/applications
).
Quindi, per ovviare a questo, possiamo usare una piccola funzione hacker di Bash che installa temporaneamente il file .desktop desiderato prima di avviarlo . Il modo "corretto" per installare un file .desktop è tramite desktop-file-install
ma lo 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
)
}
Puoi usarlo in questo modo (e anche passare argomenti aggiuntivi o URI se vuoi):
launch PATH [URI...]
launch ./path/to/shortcut.desktop
L'alternativa manuale
Se si desidera analizzare manualmente ed eseguire un file .desktop , è possibile farlo con il seguente awk
comando:
awk '/^Exec=/ {sub("^Exec=", ""); gsub(" ?%[cDdFfikmNnUuv]", ""); exit system($0)}' app-name.desktop
Se vuoi trattare il awk
comando come uno script all-in-one; possiamo anche mostrare un messaggio di errore ed uscire con un codice di ritorno 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 \047%s\047\n", FILENAME > "/dev/stderr"} close("/dev/stderr"); exit 1}}'
I comandi di cui sopra dovranno:
- Trova la riga che inizia con Exec =
- Rimuovi Exec =
- Rimuovere tutte le variabili Exec (ad esempio
%f
, %u
, %U
). È possibile sostituirli con argomenti posizionali come previsto dalla specifica, ma in tal modo si aggiungerebbe una notevole complessità al problema. Vedi le ultime specifiche sulle voci del desktop .
- Esegui il comando
- 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 possono o non possono essere correttamente affrontati da alcune delle altre risposte. In particolare, questo comando rimuove più variabili Exec (facendo attenzione a non rimuovere altrimenti il simbolo%), eseguirà solo un singolo comando di linea Exec e si comporterà come previsto anche se il comando di linea Exec contiene uno o più segni di uguale (ad es script.py --profile=name
.).
Solo alcune altre avvertenze ... Secondo le specifiche, TryExec è:
Percorso di un file eseguibile su disco utilizzato per determinare se il programma è effettivamente installato. Se il percorso non è un percorso assoluto, il file viene cercato nella variabile di ambiente $ PATH. Se il file non è presente o non è eseguibile, la voce potrebbe essere ignorata (non utilizzata nei menu, ad esempio).
Con questo in mente, non ha senso eseguire il suo valore.
Alcune altre preoccupazioni sono Path e Terminal . Il percorso è costituito dalla directory di lavoro in cui eseguire il programma. Terminal è un valore booleano che indica se il programma viene eseguito in una finestra del terminale. Questi possono essere tutti affrontati, ma non ha senso reinventare la ruota in quanto esistono già implementazioni delle specifiche. Se vuoi implementare Path , tieni presente che system()
genera un sottoprocesso, quindi non puoi cambiare la directory di lavoro facendo qualcosa di simile system("cd \047" working_directory "\047"); system(command)
. Tuttavia presumibilmente potresti fare qualcosa del genere system("cd \047" working_directory "\047 && " command)
. Nota \ 047 sono virgolette singole (quindi il comando non si interrompe su percorsi con spazi).
L'alternativa Python
Sto rubando una pagina da Carlo qui , che ha suggerito di creare uno script Python per utilizzare il modulo gi . 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 eseguire la funzione di avvio come segue:
launch ./path/to/shortcut.desktop
Si noti che l'uso di 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 durevole.
exec
fallimento è perché exec sostituisce il processo attualmente in esecuzione con il processo specificato, quindi quello che hai fatto è stato provare a sostituire la shell con l'esecuzione del desktop come binario compilato. Il motivo per cui nonsudo exec
è stato possibile è perché è un comando incorporato della shell e non un comando binario.