O caminho certo
Você realmente deve usar gtk-launch
, se estiver disponível. Geralmente é parte do pacote libgtk-3-bin (isso pode variar de acordo com a distribuição).
gtk-launch
é usado da seguinte forma:
gtk-launch APPLICATION [URI...]
gtk-launch app-name.desktop
gtk-launch app-name
Observe que gtk-launch
requer que o arquivo .desktop esteja instalado (isto é, localizado em /usr/share/applications
ou ~/.local/share/applications
).
Então, para contornar isso, podemos usar uma pequena função Bash hackeana que instala temporariamente o arquivo .desktop desejado antes de iniciá-lo. A maneira "correta" de instalar um arquivo .desktop é através de desktop-file-install
, mas vou ignorar isso.
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
)
}
Você pode usá-lo assim (e também passar argumentos adicionais ou URIs se quiser):
launch PATH [URI...]
launch ./path/to/shortcut.desktop
A alternativa manual
Se você quiser analisar manualmente e executar um arquivo .desktop , poderá fazê-lo com o seguinte comando awk
:
awk '/^Exec=/ {sub("^Exec=", ""); gsub(" ?%[cDdFfikmNnUuv]", ""); exit system($0)}' app-name.desktop
Se você quiser tratar o comando awk
como um script all-in-one; Podemos até mostrar uma mensagem de erro e sair com um código de retorno de 1 no caso de um comando Exec não ser encontrado:
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}}'
Os comandos acima mencionados irão:
- Encontre a linha que começa com Exec =
- Remover Exec =
- Remova todas as variáveis do Exec (por exemplo,
%f
, %u
, %U
). É possível substituí-los por argumentos posicionais, como pretende a especificação, mas isso acrescentaria complexidade significativa ao problema. Veja a Especificação de entrada na área de trabalho mais recente.
- Execute o comando
- Saia imediatamente com o código de saída apropriado (para não executar várias linhas Exec )
Note que este script AWK endereça alguns casos extremos que podem ou não ser endereçados apropriadamente por algumas das outras respostas. Especificamente, esse comando remove várias variáveis Exec (tomando cuidado para não remover o símbolo%), só executará um único comando de linha Exec e se comportará como esperado, mesmo se o comando de linha Exec contém um ou mais sinais de igual (por exemplo, script.py --profile=name
).
Apenas algumas outras advertências ... De acordo com a especificação, TryExec é:
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).
Com isso em mente, não faz sentido executar seu valor.
Algumas outras preocupações são Path e Terminal . Caminho consiste no diretório de trabalho para executar o programa. Terminal é um booleano que indica se o programa é executado em uma janela de terminal. Tudo isso pode ser resolvido, mas não faz sentido reinventar a roda, pois já existem implementações da especificação. Se você quiser implementar Caminho , tenha em mente que system()
gera um subprocesso, portanto você não pode alterar o diretório de trabalho fazendo algo como system("cd 7" working_directory "7"); system(command)
. No entanto, você poderia, presumivelmente, fazer algo como system("cd 7" working_directory "7 && " command)
. Nota \ 047 são aspas simples (então o comando não quebra em caminhos com espaços).
A alternativa do Python
Estou roubando uma página do Carlo aqui , que sugeriu a criação de um script Python para fazer uso do gi . Aqui está uma maneira mínima de executar o mesmo código a partir do shell sem ter que criar um arquivo e se preocupar com 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
}
Em seguida, execute a função de inicialização da seguinte forma:
launch ./path/to/shortcut.desktop
Observe que o uso de URIs é opcional. Além disso, nenhuma verificação de erro é executada, portanto, você deve garantir que o inicializador exista e seja legível (antes de usá-lo) se quiser que seu script seja durável.