问题描述
从我可以收集的内容来看,.desktop
文件是允许自定义应用程序设置的快捷方式。例如,我的/usr/share/applications/
文件夹中有很多。
如果我在nautilus
中打开该文件夹,只需双击其相关文件即可运行这些应用程序,例如, double-clicking 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
文件?
最佳解决方案
运行的命令包含在桌面文件中,以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中详细说明 – 它们都不适用于在命令行启动。
次佳解决方案
答案应该是
xdg-open program_name.desktop
但由于a bug,这不再有效。
第三种解决方案
使用任何最新的支持gtk-launch
的ubuntu只需简单地去
gtk-launch <file>
其中是没有.desktop
部分的.desktop文件的名称
因此gtk-launch foo
打开foo.desktop
如果<file>
不在/usr/share/application
中或执行gtk-launch
的位置,则命令为gtk-launch <file> <uri>
。 (gtk-launch
文档)
可用于终端或alt + F2(alt + F2存储历史中的命令,因此很容易访问)
第四种方案
截至今天(12.10)the bug仍存在。这实际上取决于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 __name__ == "__main__":
main(*sys.argv)
该脚本需要具有可执行权限,因此我在终端中运行了此操作:
chmod +x ~/bin/run-desktop
然后我在~/.local/share/applications/run-desktop.desktop
上创建了相关的.desktop
条目:
[Desktop Entry]
Version=1.0
Name=run-desktop
Exec=run-desktop %U
MimeType=application/x-desktop
Terminal=false
Type=Application
最后,我将条目作为默认处理程序关联到[Default Applications]部分下的〜/.local /share /applications /mimeapps.list中,如下所示:
[Default Applications]
....
application/x-desktop=run-desktop.desktop
现在:
-
xdg-open
something.desktop按预期工作 -
可执行桌面条目顶部的
#!/usr/bin/xdg-open
hashbang也适用
当gvfs-open
解决这个错误时,这将是无用的工作,但同时……
第五种方案
尽管OP并没有问KDE,但对于任何运行KDE的人,都可以使用以下命令:
kioclient exec <path-to-desktop-file>
第六种方案
正确的方式
如果可用,您应该真的使用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
中)。
所以为了解决这个问题,我们可以使用一个黑客小Bash函数,在启动它之前临时安装所需的.desktop文件。 “correct”安装.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
命令视为all-in-one脚本;我们甚至可以显示错误消息,并在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}}'
上述命令将会:
-
找到以Exec =开头的行
-
删除Exec =
-
删除任何Exec变量(例如
%f
,%u
,%U
)。按照说明书的要求,可以用位置参数替换这些参数,但这样做会增加问题的复杂性。查看最新的Desktop Entry Specification。 -
执行该命令
-
立即用适当的退出代码退出(以免执行多个Exec行)
请注意,这个AWK脚本解决了一些其他答案可能会或可能不会被正确解决的边情况。具体来说,该命令删除多个Exec变量(注意不要删除%符号),只执行一个Exec行命令,并且即使Exec行命令包含一个或多个等号(如script.py --profile=name
) 。
只是其他一些警告……根据规范,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).
考虑到这一点,执行它的价值是没有意义的。
其他一些问题是路径和终端。 Path由运行程序的工作目录组成。Terminal是一个布尔值,表示程序是否在终端窗口中运行。这些都可以解决,但重新发明轮子是没有意义的,因为已经有规范的实现。如果您确实想要实现Path,请记住system()
会生成一个子进程,因此您不能通过执行类似system("cd \047" working_directory "\047"); system(command)
的操作来更改工作目录。但是,你可能会做一些像system("cd \047" working_directory "\047 && " command)
。注意\ 047是单引号(所以命令不会在具有空格的路径上中断)。
Python选择
我偷了Carlo here的一个页面,他建议创建一个Python脚本来使用gi模块。这是从shell执行相同代码而不必创建文件并担心I /O的最简单方法。
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
}
然后执行启动器功能,如下所示:
launch ./path/to/shortcut.desktop
请注意,使用URI是可选的。此外,不执行错误检查,因此如果希望脚本持久耐用,则需要确保启动程序存在且可读(在使用之前)。
第七种方案
exo-open [[path-to-a-desktop-file]...]
似乎在13.10版本中工作,如果安装了exo-utils(就像Xubuntu一样)。
第八种方案
您可以使用dex。
dex foo.desktop
第九种方案
对Hamish的答案的补充。
鉴于deskopen脚本,您可以使用它作为.desktop文件中的shebang行的引用,因为注释字符仍然是#
。也就是说,把它作为.desktop文件的第一行:
#!/usr/bin/env deskopen
然后将.desktop文件标记为可执行文件(例如,使用chmod +x whatever.desktop
),然后您可以
path/to/whatever.desktop
和voilà – 应用程序将打开! (完成我指定的图标文件,但我不知道如何。)
现在,如果您还希望deskopen通过任何命令行参数,则可以改为使用此slightly-modified版本:
#!/bin/sh
desktop_file=$1
shift
`grep '^Exec' "${desktop_file}" | sed 's/^Exec=//' | sed 's/%.//'` "$@" &
另外,我尝试使用"#{@:2}"
而不是shift
ing,但它一直给我’bad substitution’ …
第十种方案
目前还没有一个应用程序能够完成您在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会话初始化脚本中调用它。