我目前正在尝试为我的函数编写一个函数bash 配置文件这会导致作为参数传递的 OSX LaunchAgent 重新启动。这可能有点毫无意义,但对于我来说,我不想再为它编写长路径launchctl un/load
除了对 launchctl 的最后调用之外,我几乎已经完成了所有工作。这是函数脚本和随后的错误消息:
功能
launchctl_mgr() {
failure() {
local lineno=$1
local msg=$2
echo "Failed at $lineno: $msg"
}
trap 'failure ${lineno} "$BASH_COMMAND"' ERR
trap 'trap - ERR' RETURN
instruction=$1
filepath=$2;
#test whether the file argument is already a file or not and whether or not it is actually$
if [[ ! -f $2 ]]
then
if [[ -f ~/Library/LaunchAgents/$2.plist ]]
then
filepath="~/Library/Launchagents/$filepath.plist"
echo "found!: $filepath"
elif [[ -f /Library/LaunchAgents/$2.plist ]]
then
filepath="/Library/LaunchAgents/$filepath.plist"
else
echo "debug: ~/Library/LaunchAgents/$filepath.plist"
echo "Filename supplied was not valid as a launchagent"
return 1
fi
fi
if [[ $instruction=="restart" || instruction=="unload" ]]
then
echo "instruction is $instruction"
echo "filepath is $filepath"
launchctl stop $filepath
launchctl unload $filepath
if [[ instruction=="restart" ]]
then
launchctl load $filepath
launchctl start $filepath
fi
fi
}
输出/错误
____________________ => launchctl_mgr unload local.unminimise
found!: ~/Library/Launchagents/local.unminimise.plist
instruction is unload
filepath is ~/Library/Launchagents/local.unminimise.plist
Failed at launchctl stop $filepath:
/Users/[current_user]/~/Library/Launchagents/local.unminimise.plist: No such file or directory
/Users/[current_user]/~/Library/Launchagents/local.unminimise.plist: No such file or directory
Failed at launchctl start $filepath:
(“[current_user]”替换我的实际用户帐户名)
正如您在 launchctl 中看到的,无论是 bash 还是 launchctl,当前目录路径和我输入 launchctl 的路径字符串都连接在一起,从而导致错误。文件路径字符串被打印出来并且在之前的行中看起来没问题
答案1
在 [[ ... ]] 测试中,您需要在 == 之前和之后有空格,否则它们只会被评估为字符串,并且非空始终为真。
例如:
$ instruction=whatever $ [[ $instruction=="restart" ]] && echo true || echo false true
这相当于:
$ [[ whatever=="restart" ]] && echo true || echo false true
它也相当于以下内容(以及其他几个变体):
$ [[ -n 'whatever=="restart"' ]] && echo true || echo false true
在所有这些情况下,您都不会检查是否
$instruction
等于“重新启动”。相反,您正在测试字符串是否whatever=="restart"
非空。该字符串恰好包含字符序列==
,但这并不重要。它们只是嵌入字符串中的字符,没有特殊含义。与之比较:
$ instruction=whatever $ [[ $instruction == "restart" ]] && echo true || echo false false $ instruction=restart $ [[ $instruction == "restart" ]] && echo true || echo false true
脚本中还有一些地方
$
缺少 before 变量。例如if [[ $instruction=="restart" || instruction=="unload" ]]
这需要前后空格
==
和a$
在第二个之前instruction
:if [[ $instruction == "restart" || $instruction == "unload" ]]
同样在这里:
if [[ instruction=="restart" ]]
那应该是:
if [[ $instruction == "restart" ]]
使用变量(和 shell 位置参数)时需要用双引号引起来。例如
local lineno="$1" local msg="$2"
和:
instruction="$1" filepath="$2"
和:
launchctl stop "$filepath" launchctl unload "$filepath"
为什么要把它写成一个函数而不是一个独立的脚本?您需要它来更改当前 shell 的环境吗?
编写函数没有什么问题,但除非你想如果要更改当前 shell 的环境,您最好使用单独脚本提供的隔离,这样您就不会意外更改环境。
或声明全部你的函数变量(包括
$instruction
和$filepath
)local
但是这只适用于防止变量被改变,函数仍然可以改变其他东西,比如shell的当前目录。
答案2
非常感谢 Cas 的回答和 bash 语法方面的帮助,但我从一些修补中发现波形符in~/Library/LaunchAgents/[agent]
是导致脚本实际按预期工作而不是抛出串联路径的问题的原因。
由于某种原因,波形符不会在 launchctl 地址参数中展开,因此如果其他人遇到此问题,请使用:
$HOME/Library/LaunchAgents/[agent]
在 launchctl 命令中寻址您的代理。
该路径如所描述的这里在下面“旧命令”然后“加载”
注意:对于我的脚本来说,至少这实际上并没有解决 launchctl 抛出错误,但确实修复了功能。尽管文档说:
由于先前实现中的错误以及客户对这些错误的长期期望,由于使用不当,加载和卸载子命令只会返回非零退出代码。否则,始终返回零。
..我设置的 ERR 陷阱始终会抛出错误而没有消息,即使脚本按预期工作并且手动复制命令不会给出任何错误消息。
也许有人可以弥补我的无知,但如果您在我的建议后仍然感到头疼,请尝试launchctl list | grep [agent_name]
看看是否达到了预期的效果