![当从 ~/.zshrc 执行 sudo 函数时,“找不到命令”](https://linux22.com/image/96887/%E5%BD%93%E4%BB%8E%20~%2F.zshrc%20%E6%89%A7%E8%A1%8C%20sudo%20%E5%87%BD%E6%95%B0%E6%97%B6%EF%BC%8C%E2%80%9C%E6%89%BE%E4%B8%8D%E5%88%B0%E5%91%BD%E4%BB%A4%E2%80%9D.png)
我的 中有一个函数~/.zshrc
:
findPort() {
lsof -t -i :$1
}
通常的调用是findPort 3306
.
我想以更高的权限运行它。但我得到“命令未找到”。
➜ git
答案1
sudo
直接运行命令,而不是通过 shell,即使它运行一个 shell 来运行该命令,它也将是一个新的 shell 调用,而不是读取您的命令~/.zshrc
(即使它启动了一个交互式 shell,它可能会root
读取~/.zshrc
,不是你的,除非你配置sudo
为不重置$HOME
变量)。
在这里,您需要告诉sudo
启动一个新的zsh
shell,并告诉它在运行该函数之前zsh
读取您的~/.zshrc
内容:
sudo zsh -c '. $0; "$@"' ~/.zshrc findPort 3306
或者:
sudo zsh -c '. $0; findPort 3306' ~/.zshrc
zsh
或者与调用的新函数共享当前的 zsh 函数sudo
:
sudo zsh -c "$(functions); findPort 3306"
虽然你可能会得到一个arg 列表太长如果定义了很多函数(例如使用完成系统时),则会出现错误。因此,您可能希望将其限制为该findPort
函数(以及它所依赖的所有其他函数(如果有)):
sudo zsh -c "$(functions findPort); findPort 3306"
你还可以这样做:
sudo zsh -c "(){$functions[findPort]} 3306"
将函数的代码嵌入findPort
到匿名函数您将 3306 参数传递给它。甚至:
sudo zsh -c "$functions[findPort]" findPort 3306
(内联脚本传递给-c
是函数体)。
您可以使用辅助函数,例如:
zsudo() sudo zsh -c "$functions[$1]" "$@"
不使用:
sdo() { sudo zsh -c "(){$functions[$1]} ${@:2}" }
因为 的参数sdo
将经历另一个级别的 shell 解析。比较:
$ e() echo "$@"
$ sdo e 'tname;uname'
tname
Linux
$ zsudo e 'tname;uname'
tname;uname
答案2
对我来说,一个非常简单的解决方案是使用 调用交互式 shell sudo -s
,它似乎适用于我的 macOS 捆绑版本的 zsh (5.2)。这为我提供了我的~/.zshrc
.
从 sudo 手册页来看,它并没有真正暗示这种行为:
-s, --shell
运行由 SHELL 环境变量指定的 shell(如果已设置)或由调用用户的密码数据库条目指定的 shell。如果指定了命令,则会通过 shell 的 -c 选项将其传递到 shell 执行。如果未指定命令,则执行交互式 shell。
我不确定您的用例是什么,但我怀疑您正在寻找交互式解决方案。
答案3
我能够制作一个可重复使用的速记对于 Stéphane Chazelas 中描述的解决方案之一回答。 [编辑:Stéphane 迭代了我提出的原始快捷方式;这里描述的代码是他制作的更新版本]
将其放入您的~/.zshrc
:
sdo() sudo zsh -c "$functions[$1]" "$@"
现在您可以用作sdo
“sudo
仅用于用户定义的函数”。
要确认其sdo
有效:您可以在打印您的用户名的用户定义函数上进行尝试。
➜ birch@server ~/
答案4
这似乎对我有用:
function sudo (){
args="$@"
/run/wrappers/bin/sudo -u "$USER" zsh -i -c "$args"
}