正确的方法
如果可用,您应该真正使用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文件。在安装
.desktop文件的“正确”方法是通过
desktop-file-install
,但我将忽略它。
launch(){
(
appdir=$HOME/.local/share/applications
template=launcher-XXXXXX.desktop
[[ $1 = *.desktop && -f $1 && -r $1 && -s $1 ]] || {
echo "ERROR: you have not supplied valid .desktop file" >&2
return 1
}
trap 'rm "$launcherfile" &>/dev/null' EXIT
launcherfile=$(mktemp -p "$appdir" "$template")
launchername=${launcherfile##*/}
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}}'
上述命令将会:
- 查找以 Exec= 开头的行
- 删除 Exec=
- 删除任何 Exec 变量(例如
%f
, %u
, %U
)。根据规范,可以用位置参数替换这些变量,但这样做会给问题增加相当复杂性。请参考最新的桌面入口规范。
- 执行命令
- 立即以适当的退出码退出(以避免执行多个 Exec 行)
注意,此 AWK 脚本解决了一些其他答案可能没有正确处理的特殊情况。具体来说,该命令会删除多个 Exec 变量(同时确保不删除 % 符号),只会执行单个 Exec 行命令,并且即使 Exec 行命令中包含一个或多个等号(例如 script.py --profile=name
),也会按预期运行。
只是还有一些其他要注意的地方... 根据规范,
TryExec 是:
磁盘上可执行文件的路径,用于确定程序是否安装。如果路径不是绝对路径,则会在 $PATH 环境变量中查找该文件。如果文件不存在或者不可执行,该条目可能会被忽略(例如,在菜单中不使用)。
考虑到这一点,执行它的值就没有意义了。
一些其他的问题是
路径和
终端。
路径包括运行程序的工作目录。
终端是一个布尔值,表示程序是否在终端窗口中运行。这些都可以解决,但没有必要重新发明轮子,因为已经有了规范的实现。如果您确实想要实现
路径,请记住
system()
会生成一个子进程,所以您不能通过像
system("cd \047" working_directory "\047"); system(command)
这样的方式来更改工作目录。不过,您可以尝试像
system("cd \047" working_directory "\047 && " command)
这样的方式。注意\047是单引号(这样命令就不会在带有空格的路径上中断)。
Python替代方案
我从Carlo 这里那里借鉴了一个方法,他建议创建一个使用gi模块的Python脚本。以下是一种在不创建文件和担心I/O的情况下从shell执行相同代码的最简方式。
launch(){
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是可选的。此外,没有进行错误检查,所以如果您希望脚本具有耐久性,在使用之前,请确保启动器存在且可读。
exec
失败的原因是因为exec
会用指定的进程替换当前正在运行的进程,所以你试图用编译好的二进制文件来替换你的shell,从而运行桌面。你无法使用sudo exec
是因为它是一个shell内置命令,而不是一个二进制命令。 - Daenyth