it-swarm.cn

在终端中运行.desktop文件

根据我的收集,.desktop文件是允许自定义应用程序设置的快捷方式。例如,我的/usr/share/applications/文件夹中有很多它们。

如果我在nautilus中打开该文件夹,我可以通过双击其关联文件来运行这些应用程序,例如双击firefox.desktop运行Firefox。但是,我找不到通过终端做同样事情的方法。

如果我执行gnome-open foo.desktop,它只会打开foo.desktop作为文本文件。如果我使它可执行,然后在bash中运行它只是失败(这是预期的,它显然不是bash脚本)。
编辑:执行exec /fullpath/foo.desktop会给我一条Permission denied消息,即使我将所有权更改为自己。如果我创建可执行文件并执行相同的命令,我使用的终端选项卡只是关闭(我猜它崩溃了)。最后,如果我执行Sudo exec /fullpath/foo.desktop,我会收到报告Sudo: exec: command not found的错误。

这是我的问题,如何从终端运行foo.desktop文件?

140
Malabarba

运行的命令包含在桌面文件中,前面是Exec=,因此您可以通过以下方式提取和运行该命令:

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

打破这一点

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

你可以将它放在一个文件中,比如~/bin/deskopen和内容

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

然后使其可执行

chmod +x ~/bin/deskopen

然后你可以这样做,例如

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

参数(%u%F等)详见 http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html#exec-variables - 没有它们与在命令行启动相关。

54
Hamish Downer

答案应该是

xdg-open program_name.desktop

但由于 一个bug 这不再有效。

83
Richard Holloway

对于任何最近支持gtk-launch的ubuntu,只需简单地去

gtk-launch <file>其中是没有.desktop部分的.desktop文件的名称

所以gtk-launch foo打开foo.desktop

gtk-launch文档

.desktop应位于/ usr/share/applications,/ usr/local/share/applications或〜/ .local/share/applications( - 显然,如果需要,您可以使用.desktop。

可从终端或alt + F2使用(alt + F2存储历史命令,因此很容易访问)

73
doug

截至今天(12.10) 错误 仍然存在。事实上,这取决于gvfs-open(由xdg-open调用)的工作方式。

尽管如此,我还是快速解决了一下(从nautilus源代码中窃取灵感)。它有点令人费解,但在Ubuntu 12.10上运行完美,在Unity启动器上添加了一个有意义的图标(不再是?)。

首先,我使用Gio编写了一个python脚本并将其保存为~/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 __== "__main__":
    main(*sys.argv)

该脚本需要具有可执行权限,因此我在终端中运行它:

chmod +x ~/bin/run-desktop

然后我在.desktop上创建了相对~/.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

最后,我将条目作为~/.local/share/applications/mimeapps.list部分[Default Applications]下的默认处理程序关联为:

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

现在:

  • xdg-open something.desktop按预期工作
  • #!/usr/bin/xdg-open hashbang位于可执行桌面条目之上

gvfs-open解决错误时,这将是无用的工作,但同时......

38
Carlo Pellegrini

正确的方式

如果可用,你应该使用gtk-launch。它通常是包的一部分libgtk-3-bin(这可能因发行版而异)。

gtk-launch使用如下:

gtk-launch APPLICATION [URI...]
gtk-launch app-name.desktop
gtk-launch app-name

请注意,gtk-launch需要安装。desktop文件(即位于/usr/share/applications~/.local/share/applications)。

因此,为了解决这个问题,我们可以使用一个hackish little Bash函数,在启动之前临时安装所需的。desktop文件。安装。桌面文件的“正确”方法是通过desktop-file-install,但我将忽略它。

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

    )

}

您可以像这样使用它(如果需要,还可以传递其他参数或URI):

launch PATH [URI...]
launch ./path/to/shortcut.desktop

手动替代方案

如果要手动解析并执行。desktop文件,可以使用以下awk命令执行此操作:

awk '/^Exec=/ {sub("^Exec=", ""); gsub(" ?%[cDdFfikmNnUuv]", ""); exit system($0)}' app-name.desktop

如果要将awk命令视为一体化脚本;我们甚至可以显示一条错误消息,如果找不到Exec命令,则返回代码为1:

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}}'

上述命令将:

  1. 找到以开头的行Exec =
  2. 删除Exec =
  3. 删除所有Exec变量(例如%f%u%U)。可以根据规范的意图用位置参数替换它们,但这样做会增加问题的复杂性。查看最新的 桌面条目规范
  4. 执行命令
  5. 立即退出相应的退出代码(以便不执行多个Exec行)

请注意,此AWK脚本解决了一些Edge案例,这些案例可能会或可能不会被其他一些答案正确解决。具体来说,这个命令删除了多个Exec变量(注意不要删除%符号),只会执行一个Exec line命令,即使Exec行命令包含一个或多个等号(例如script.py --profile=name),也会按预期运行。

其他几点需要注意......根据规范,TryExec是:

磁盘上可执行文件的路径,用于确定程序是否实际安装。如果路径不是绝对路径,则在$ PATH环境变量中查找该文件。如果文件不存在或者文件不可执行,则可以忽略该条目(例如,不在菜单中使用)。

考虑到这一点,执行它的价值是没有意义的。

其他一些问题是PathTerminal路径由运行程序的工作目录组成。终端是一个布尔值,表示程序是否在终端中运行窗口。这些都可以解决,但重新发明轮子是没有意义的,因为已经有规范的实施。如果你想实现Path,请记住system()产生一个子进程,因此你不能通过像system("cd \047" working_directory "\047"); system(command)这样的东西来改变工作目录。但是你可能会做system("cd \047" working_directory "\047 && " command)之类的事情。注意\ 047是单引号(因此命令不会在带空格的路径上中断)。

Python替代

我正在偷一个来自Carlo的页面 这里 ,他建议创建一个Python脚本来使用gi模块。这是从Shell执行相同代码的最小方法,无需创建文件并担心I/O.

launch(){

# Usage: launch PATH [URI...]

python - "[email protected]" <<EOF
import sys
from gi.repository import Gio
Gio.DesktopAppInfo.new_from_filename(sys.argv[1]).launch_uris(sys.argv[2:])
EOF

}

然后按如下方式执行启动器功能:

launch ./path/to/shortcut.desktop

请注意,URI的使用是可选的。此外,不执行错误检查,因此如果您希望脚本持久,您将需要确保启动程序存在且可读(在使用之前)。

31
Six

虽然OP没有询问KDE,但对于运行KDE的任何人来说,可以使用以下命令:

kioclient exec <path-to-desktop-file>

在Fedora上,它包含在kde-runtime rpm中。

26
Raman

你可以使用 dex

dex foo.desktop
13
couac
exo-open [[path-to-a-desktop-file]...]

如果安装了exo-utils,那么似乎在13.10版本中工作(就像Xubuntu一样)。

13
jarno

对Hamish的回答补遗。

给定deskopen脚本,您可以在。desktop文件中使用对它的引用作为Shebang行,因为注释字符仍然是#。也就是说,把它作为。desktop文件的第一行:

#!/usr/bin/env deskopen

然后将。desktop文件标记为可执行文件(例如,使用chmod +x whatever.desktop),然后就可以了

path/to/whatever.desktop

voilà - 该应用程序将打开! (完成我指定的图标文件,但我不知道如何。)

现在,如果您还希望deskopen通过任何命令行参数,您可以改为使用这个稍微修改过的版本:

#!/bin/sh
desktop_file=$1
shift
`grep '^Exec' "${desktop_file}" | sed 's/^Exec=//' | sed 's/%.//'` "[email protected]" &

顺便说一句,我尝试使用"#{@:2}"而不是shifting,但它一直给我'糟糕的替代'......

8
pabst

目前没有一个应用程序可以执行您在Ubuntu归档中描述的内容。正在进行一些努力来创建一个通用解决方案,以便为不符合这些XDG规范的桌面环境(如openbox)提供集成。

Arch Linux正在开发基于python-xdg库的xdg-autostart实现。根据我的发现,这似乎尚未完全完成,但有一些成功的报告。

在gitorious(http://gitorious.org/xdg-autostart/)上还有一个xdg-autostart的C++实现,它可能会受益于更广泛的使用。

如果任何一种解决方案适合您,请考虑提交必要的工作以包含在Debian或Ubuntu中。

要使用openstart中的任一工具,您可以在/etc/xdg/openbox/autostart.sh中调用它(如果我正确阅读openbox文档)。如果这不起作用,您可以在任何openbox会话初始化脚本中调用它。

6
Emmet Hikory

我没有立即解决方案满足“使用标准命令”的要求,但如果你确实想要最低限度地解析.desktop文件或想要创建一个Bash别名,那么以下内容应该可行:

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

另一种可能有趣的方法是创建一个内核级binfmt-misc方法而不是.desktop文件上的匹配(对于那些你当前启用的模式,请参见grep -r . /proc/sys/fs/binfmt_misc/)。

在一天结束时,某事某处必须解析.desktop文件,这只是一个“标准/默认”如何的问题。

6
sladen

我从上面的 Carlo's回答 获取了脚本,并试图改进它以供我自己的桌面使用。

此版本的脚本将允许您运行任何应用程序,就像您在HUD上输入它一样,只要它可能是第一个结果。它还允许您传递不支持URI的.desktop文件的文件参数。

#!/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 __== "__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)
2
Fordi

(从这里的各种其他答案编译)

根据您的系统以及系统上可能存在或可能不存在的各种错误,请尝试以下操作,直到其中一个工作:

  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

请注意,在Ubuntu系统上,“开始菜单”桌面启动器在/usr/share/applications/中可用。

例如,要显示上述哪些命令在我的Ubuntu 14.04系统上有效或无效,以下是对我的以下调用的结果:

  1. xdg-open /usr/share/applications/Eclipse_for_cpp.desktop#由于bug而失败(试图让我保存这个.desktop文件)
  2. exo-open /usr/share/applications/Eclipse_for_cpp.desktop#Works
  3. gtk-launch /usr/share/applications/Eclipse_for_cpp.desktop#失败“gtk-launch:没有这样的应用程序”
  4. kioclient exec /usr/share/applications/Eclipse_for_cpp.desktop#Works
  5. dex /usr/share/applications/Eclipse_for_cpp.desktop #Fails,&Sudo apt install dex找不到包dex
1
Gabriel Staples

在尝试测试这些文件时,我找到了最简单的方法来检查DM或会话管理器是否会按照我的预期在UI文件夹浏览器中打开周围的目录,然后双击打开它们。

如果您在命令行中:gvfs-open .gnome-open .将在配置的文件夹浏览器中打开它。

Sed的东西不会反映DM的行为,包括像逃脱和引用这样的东西,你真的不想要替代行为。它不是命令行,但它确实验证了事情。我还发现设置Terminal=true对调试很有用。

1
Danny Staple

这个 SO答案 是我明确表示的:不要尝试执行桌面文件,执行桌面文件中指向的文件。

例如,执行/home/jsmith/Desktop/x11vnc.sh

Exec=/home/jsmith/Desktop/x11vnc.sh
1
user119824

确保桌面文件指向的脚本也是可执行的。

如果仍然不起作用。通过更改Terminal=true使终端中的桌面​​文件可运行,并将其放在bash脚本中。运行脚本以捕获错误输出。更正错误时更改回来。

0
hakunami

Hamish的答案很棒,但我想建议一个更简单的替代方案,涉及的管道更少:

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

在这种情况下,awk搜索以Exec开头的行,然后我们只是在该行之后打印字段,使用for循环和=我们打印字段2,即在该字段之后的任何内容。命令末尾的大括号$(...)是参数替换,因此Shell将执行awk命令返回的任何内容;在这种情况下,它返回Exec=之后的实际命令。

在极少数情况下,可能会有多个=符号,这仍然是可能的。为此,我建议

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