La direccion correcta
Realmente deberías estar usando gtk-launch
si está disponible. Por lo general, forma parte del paquete libgtk-3-bin (esto puede variar según la distribución).
gtk-launch
se usa de la siguiente manera:
gtk-launch APPLICATION [URI...]
gtk-launch app-name.desktop
gtk-launch app-name
Tenga en cuenta que gtk-launch
requiere la instalación del archivo .desktop (es decir, ubicado en /usr/share/applications
o ~/.local/share/applications
).
Por lo tanto, para evitar esto, podemos usar una pequeña función de Bash que instala temporalmente el archivo .desktop deseado antes de iniciarlo. La forma "correcta" de instalar un archivo .desktop es a través de, desktop-file-install
pero voy a ignorar eso.
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 awk
comando:
awk '/^Exec=/ {sub("^Exec=", ""); gsub(" ?%[cDdFfikmNnUuv]", ""); exit system($0)}' app-name.desktop
Si desea tratar el awk
comando como un script todo en uno; incluso podemos mostrar un mensaje de error y salir con un código de retorno de 1 en 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 \047%s\047\n", FILENAME > "/dev/stderr"} close("/dev/stderr"); exit 1}}'
Los comandos mencionados anteriormente:
- Encuentra la línea que comienza con Exec =
- Eliminar Exec =
- Elimine cualquier variable Exec (p
%f
. Ej . %u
, %U
). Es posible reemplazarlos con argumentos posicionales según lo previsto en la especificación, pero hacerlo agregaría una complejidad significativa al problema. Consulte la última especificación de entrada de escritorio .
- Ejecutar el comando
- Salga inmediatamente con el código de salida apropiado (para no ejecutar varias líneas Exec )
Tenga en cuenta que este script de AWK aborda algunos casos extremos que pueden o no ser abordados adecuadamente por algunas de las otras respuestas. 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 esperaba 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 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 (por ejemplo, no se puede usar en los menús).
Con eso en mente, no tiene sentido ejecutar su valor.
Algunas otras preocupaciones son Path y Terminal . La 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 Path , tenga en cuenta que system()
genera un subproceso, por lo que no puede cambiar el directorio de trabajo haciendo algo como system("cd \047" working_directory "\047"); system(command)
. Sin embargo, presumiblemente podrías hacer algo así system("cd \047" working_directory "\047 && " command)
. Nota \ 047 son comillas simples (por lo que el comando no se rompe en las rutas con espacios).
La alternativa a Python
Aquí estoy robando una página de Carlo , quien sugirió crear un script de Python para usar el módulo gi . Aquí hay una forma mínima de ejecutar el mismo código desde el shell sin tener que crear un archivo y preocuparse por las E / S.
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
}
Luego ejecute la función del iniciador 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, por lo que querrá asegurarse de que el iniciador exista y sea legible (antes de usarlo) si desea que su script sea duradero.
exec
falló es porque exec reemplaza el proceso que está ejecutando actualmente con el proceso que especificó, por lo que lo que hizo fue intentar reemplazar su shell con la ejecución del escritorio como un binario compilado. La razón por la que no pudosudo exec
es porque es un shell incorporado y no un comando binario.