O Caminho Certo
Você realmente deveria estar usando gtk-launch
se estiver disponível. Geralmente faz parte do pacote libgtk-3-bin (isso pode variar de acordo com a distribuição).
gtk-launch
é usado da seguinte maneira:
gtk-launch APPLICATION [URI...]
gtk-launch app-name.desktop
gtk-launch app-name
Observe que gtk-launch
requer que o arquivo .desktop seja instalado (ou seja, localizado em /usr/share/applications
ou ~/.local/share/applications
).
Portanto, para contornar isso, podemos usar uma pequena função Bash que instala temporariamente o arquivo .desktop desejado antes de iniciá-lo. A maneira "correta" de instalar um arquivo .desktop é via desktop-file-install
mas eu vou ignorá-lo.
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 transmitir argumentos adicionais ou URIs, se desejar):
launch PATH [URI...]
launch ./path/to/shortcut.desktop
A alternativa manual
Se você deseja analisar e executar manualmente um arquivo .desktop , pode fazê-lo com o seguinte awk
comando:
awk '/^Exec=/ {sub("^Exec=", ""); gsub(" ?%[cDdFfikmNnUuv]", ""); exit system($0)}' app-name.desktop
Se você deseja tratar o awk
comando como um script all-in-one; podemos até mostrar uma mensagem de erro e sair com um código de retorno 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 \047%s\047\n", FILENAME > "/dev/stderr"} close("/dev/stderr"); exit 1}}'
Os comandos acima mencionados:
- Encontre a linha começando com Exec =
- Remover Exec =
- Remova todas as variáveis Exec (por exemplo
%f
, %u
, %U
). É possível substituí-los por argumentos posicionais, conforme a especificação pretende, mas isso adicionaria complexidade significativa ao problema. Consulte a última especificação de entrada da área de trabalho .
- Execute o comando
- Sair imediatamente com o código de saída apropriado (para não executar várias linhas Exec )
Observe que esse script AWK aborda alguns casos extremos que podem ou não ser tratados adequadamente por algumas das outras respostas. Especificamente, esse comando remove várias variáveis Exec (tomando cuidado para não remover o símbolo%), executará apenas um único comando de linha Exec e se comportará conforme o esperado, mesmo que o comando Exec line contenha um ou mais sinais de igual (por exemplo script.py --profile=name
).
Apenas algumas outras advertências ... De acordo com a especificação, o TryExec é:
Caminho para um arquivo executável no disco usado para determinar se o programa está realmente instalado. Se o caminho não for absoluto, o arquivo será procurado na variável de ambiente $ PATH. Se o arquivo não estiver presente ou não for executável, a entrada poderá ser ignorada (não ser usada em menus, por exemplo).
Com isso em mente, não faz sentido executar seu valor.
Algumas outras preocupações são Caminho e Terminal . O 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 há sentido em reinventar a roda, pois já existem implementações da especificação. Se você deseja implementar o Path , lembre-se de que system()
gera um subprocesso, para que você não possa alterar o diretório de trabalho fazendo algo parecido system("cd \047" working_directory "\047"); system(command)
. No entanto, você provavelmente poderia fazer algo assim system("cd \047" working_directory "\047 && " command)
. Nota \ 047 são aspas simples (portanto, o comando não quebra nos caminhos com espaços).
A Alternativa Python
Estou roubando uma página de Carlo aqui , que sugeriu a criação de um script Python para usar o módulo gi . Aqui está uma maneira mínima de executar o mesmo código do shell sem precisar 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 do iniciador da seguinte maneira:
launch ./path/to/shortcut.desktop
Observe que o uso de URIs é opcional. Além disso, nenhuma verificação de erro é realizada, portanto, você deve garantir que o iniciador exista e seja legível (antes de usá-lo) se desejar que seu script seja durável.
exec
falhou é porque o exec substitui o processo em execução pelo processo especificado, portanto, o que você fez foi tentar substituir o shell pela execução da área de trabalho como um binário compilado. A razão pela qual você não conseguiusudo exec
é porque é um shell embutido e não um comando binário.