Executando um arquivo .desktop no terminal

136

Pelo que consigo reunir, .desktop arquivos são atalhos que permitem que as configurações do aplicativo sejam personalizadas. Por exemplo, eu tenho muitos deles na minha pasta /usr/share/applications/ .

Se eu abrir essa pasta em nautilus , posso executar esses aplicativos apenas clicando duas vezes no arquivo associado, por exemplo, clicando duas vezes em firefox.desktop executa o Firefox. No entanto, não consigo encontrar uma maneira de fazer a mesma coisa via terminal.

Se eu fizer gnome-open foo.desktop , ele simplesmente abrirá foo.desktop como um arquivo de texto. Se eu torná-lo executável e, em seguida, executá-lo no bash ele simplesmente falha (o que é esperado, claramente não é script bash).
EDIT: Fazendo exec /fullpath/foo.desktop me dá uma mensagem Permission denied , mesmo se eu mudar a propriedade para mim mesmo. Se eu tornar executável e fizer o mesmo comando, a guia do terminal que estou usando simplesmente fecha (acho que ele falha). Finalmente, se eu fizer sudo exec /fullpath/foo.desktop , receberei um erro informando sudo: exec: command not found .

Essa é a minha pergunta, como posso executar um arquivo foo.desktop do terminal?

    
por Malabarba 04.10.2010 / 15:58

17 respostas

52

O comando que é executado está contido dentro do arquivo da área de trabalho, precedido por Exec= , então você pode extrair e executar isso por:

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

Para quebrar isso

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

Você pode colocar isso em um arquivo, digamos ~/bin/deskopen com o conteúdo

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

Em seguida, torne-o executável

chmod +x ~/bin/deskopen

E então você poderia fazer, por exemplo

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

Os argumentos ( %u , %F etc) estão detalhados em link - nenhum deles é relevante para o lançamento na linha de comando.

    
por Hamish Downer 04.10.2010 / 16:52
77

A resposta deve ser

xdg-open program_name.desktop

Mas devido a um erro , isso não funciona mais.

    
por Richard Holloway 04.10.2010 / 17:28
68

Com qualquer ubuntu recente que suporte gtk-launch simplesmente vá

gtk-launch <file> onde é o nome do arquivo .desktop sem a .desktop part

Então, gtk-launch foo abre foo.desktop

( gtk-launch documentation )

O .desktop deve estar em / usr / share / applications, / usr / local / share / applications ou ~ / .local / share / applications (- aparentemente você pode usar o .desktop se desejar.

Utilizável a partir do terminal ou alt + F2 (o comando alt + F2 armazena no histórico é facilmente acessível)

    
por doug 02.12.2013 / 23:32
38

A partir de hoje (12.10) o bug ainda está presente. De fato, isso depende de como o gvfs-open (chamado por xdg-open ) funciona.

Ainda assim, consegui uma solução rápida (roubando inspiração do código fonte do nautilus). É um pouco confuso, mas funciona perfeitamente no Ubuntu 12.10, adicionando um ícone significativo (não mais ? ) no iniciador Unity.

Primeiro, eu escrevi um script python usando Gio e o coloquei como ~/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)

O script precisa ter a permissão executável, então eu corri isso em um terminal:

chmod +x ~/bin/run-desktop

Em seguida, criei a entrada relativa .desktop em ~/.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

Por fim, associei a entrada como o manipulador padrão em ~/.local/share/applications/mimeapps.list na seção [Default Applications] como:

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

Agora:

  • xdg-open something.desktop funciona como esperado
  • %código% hashbang sobre uma entrada de desktop executável também funciona

Será um trabalho inútil quando #!/usr/bin/xdg-open resolver o bug, mas enquanto isso ...

    
por Carlo Pellegrini 11.01.2013 / 10:06
29

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:

  1. Encontre a linha que começa com Exec =
  2. Remover Exec =
  3. 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.
  4. Execute o comando
  5. 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.

    
por Six 21.08.2015 / 21:33
26

Enquanto o OP não estava perguntando sobre o KDE, para qualquer um que esteja executando o KDE, o seguinte comando pode ser usado:

kioclient exec <path-to-desktop-file>

No Fedora, isso está incluído no kde-runtime rpm.

    
por Raman 23.02.2014 / 19:09
13

Você pode usar dex .

dex foo.desktop
    
por couac 26.01.2015 / 00:17
12
exo-open [[path-to-a-desktop-file]...]

parece funcionar na versão 13.10, se o exo-utils estiver instalado (como é o caso do Xubuntu).

    
por jarno 22.12.2013 / 16:45
8

Adendo à resposta de Hamish.

Dado o script deskopen, você pode usar uma referência a ele como a linha shebang em um arquivo .desktop # . Ou seja, coloque isso como a primeira linha do arquivo .desktop :

#!/usr/bin/env deskopen

Em seguida, marque o arquivo .desktop como executável (por exemplo, com um chmod +x whatever.desktop ) e, em seguida, você pode

path/to/whatever.desktop

e voilà - O aplicativo será aberto! (Completo com o arquivo de ícone que eu especifiquei, embora eu não tenha ideia de como).

Agora, se você também quiser que o deskopen passe por qualquer parâmetro de linha de comando, poderá usar essa versão ligeiramente modificada:

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

Como um aparte, eu tentei usar "#{@:2}" em vez de shift ing, mas ele continuou me dando 'má substituição' ...

    
por pabst 09.02.2012 / 21:12
6

Atualmente, não há um aplicativo que faça o que você descreve nos arquivos do Ubuntu. Há alguns esforços em andamento para criar uma solução geral para fornecer integração para ambientes de desktop (como openbox) que não são compatíveis com essas especificações de XDG.

O Arch Linux está trabalhando em uma implementação do xdg-autostart baseada nas bibliotecas python-xdg. Pelo que eu posso encontrar, isso parece ainda não totalmente completo, mas tem alguns relatos de sucesso.

Existe também uma implementação em C ++ do xdg-autostart on gitorious (http://gitorious.org/xdg-autostart/) que provavelmente se beneficiaria do uso mais amplo.

Se qualquer solução funcionar para você, por favor, considere enviar o trabalho necessário para inclusão no Debian ou no Ubuntu.

Para usar qualquer ferramenta com o openstart, você pode chamá-la em /etc/xdg/openbox/autostart.sh (se eu estiver lendo a documentação da caixa de entrada corretamente). Se isso não funcionar, provavelmente você poderá chamá-lo em qualquer um dos scripts de inicialização de sessão de caixa aberta.

    
por Emmet Hikory 05.07.2011 / 07:08
6

Eu não tenho uma solução imediata atendendo ao requisito de "usando um comando padrão" , mas se você quisesse analisar minimamente os arquivos .desktop ou quisesse criar um alias de Bash, então o seguinte deve funcionar:

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

outra abordagem que poderia ser interessante seria criar um método binfmt-misc no nível do kernel que corresponde aos arquivos .desktop (consulte grep -r . /proc/sys/fs/binfmt_misc/ para os padrões que você ativou atualmente).

No final do dia, algo em algum lugar terá que analisar os arquivos .desktop , é apenas uma questão de como "padrão / padrão" é isso.

    
por sladen 09.07.2011 / 23:22
1

Ao tentar testar esses arquivos, descobri que a maneira mais simples de verificar se o DM ou o gerenciador de sessões faria o que eu esperava era abrir o diretório em torno de um navegador de pastas da interface e clicar duas vezes para abri-los.

Se você estiver em uma linha de comando: gvfs-open . ou gnome-open . irá abri-lo no navegador de pastas configurado.

A coisa sed não irá espelhar o comportamento do Mestre, incluindo coisas complicadas como fugas e citações onde você realmente não desejaria um comportamento alternativo. Não é linha de comando, mas validou as coisas. Também achei a configuração Terminal=true útil para depuração.

    
por Danny Staple 19.05.2014 / 17:20
1

Esta resposta SO é o que deixou claro para mim: não tente executar o arquivo da área de trabalho, execute o arquivo apontado no arquivo da área de trabalho.

Por exemplo, execute /home/jsmith/Desktop/x11vnc.sh

Exec=/home/jsmith/Desktop/x11vnc.sh
    
por user119824 27.06.2014 / 19:45
1

Eu peguei o script do Carlo responda acima, e tentei melhorá-lo para meu próprio uso de desktop.

Esta versão do script permite que você execute qualquer aplicativo como se você o tivesse inserido no HUD, desde que seja o primeiro resultado. Ele também permite que você passe argumentos de arquivo para arquivos .desktop que não suportam URIs.

#!/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)
    
por Fordi 18.09.2015 / 19:20
0

(Compilado das várias outras respostas aqui)

Dependendo do seu sistema e dos vários erros que podem ou não existir no seu sistema, tente o seguinte até que um deles funcione:

  1. xdg-open program_name.desktop
  2. exo-open program_name.desktop
  3. gtk-launch program_name.desktop
  4. kioclient exec program_name.desktop
  5. dex program_name.desktop

Observe que nos sistemas Ubuntu, os ativadores de área de trabalho do "menu Iniciar" estão disponíveis em /usr/share/applications/ .

Como exemplo, para mostrar quais dos comandos acima funcionam ou não no meu sistema Ubuntu 14.04, aqui estão os resultados das seguintes chamadas para mim:

  1. xdg-open /usr/share/applications/eclipse_for_cpp.desktop # Falha devido a bug (tenta fazer com que eu salve este arquivo .desktop)
  2. exo-open /usr/share/applications/eclipse_for_cpp.desktop # Works
  3. gtk-launch /usr/share/applications/eclipse_for_cpp.desktop # Falha com "gtk-launch: nenhuma aplicação desse tipo"
  4. kioclient exec /usr/share/applications/eclipse_for_cpp.desktop # Works
  5. dex /usr/share/applications/eclipse_for_cpp.desktop # Falha, & sudo apt install dex não pode localizar o pacote dex
por 01.02.2019 / 19:24
0

Verifique se o script para o qual seu arquivo de área de trabalho aponta também é executável.

Se ainda não funcionar. Torne o arquivo da área de trabalho executável no terminal alterando Terminal=true e coloque-o dentro de um script bash. Execute o script para capturar a saída de erro. Mude de volta quando os erros forem corrigidos.

    
por hakunami 26.03.2015 / 09:33
0

A resposta de Hamish é ótima, mas eu gostaria de sugerir uma alternativa mais simples, com menos envolvimento:

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

Nesse caso, awk procura pela linha que começa com Exec e, em seguida, simplesmente imprimimos campos depois dessa linha, usando para loop e = imprimimos o campo 2, ou seja, o que vier depois desse campo. As chaves nos extremos dos comandos, $(...) , são substitutos de parâmetros, assim o shell executará qualquer comando awk retornado; Nesse caso, ele retorna o comando real que vem após Exec= .

Em alguns casos raros, pode haver mais de um sinal = , o que ainda é uma possibilidade. Para isso, sugiro

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