编辑:我说 $HOME/.bin 的地方我应该写 $HOME/bin 或任何等效的东西都可以。 IE,用户 PATH 中的任何用户可写目录。
所以我有一个 bash 脚本,我将其作为 API 的客户端进行分发。当前版本安装如下curl -s http://api.blah.com/install | sudo sh
。我可能会尝试处理六个不同的包管理系统,以便它们可以仅apt-get
或brew install
在某个时刻,但现在我将使用单行,因为我希望此解决方案适用于多个系统。然而,显然有相当多的用户在 cygwin 甚至 Mac 等系统上根本没有 sudo 或者没有设置它。
该场景是用户注册我的 API,输入他们的信用卡信息。我有一个 API 的 bash 客户端,它既可以作为参考实现,也是一种使用命令行尝试 API 或部署虚拟机和 Docker 容器的方法。我想为用户创建一种简单的方法来安装 API 客户端。
例如,npm 曾经是单行安装curl http://npmjs.org/install.sh | sh
。自制软件还有一个单行安装程序ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
(请参阅http://brew.sh)。
我的安装脚本只是下载 API 客户端脚本并将其放入 /usr/bin 并使其可执行。但我认为基于 sudo 的问题以及实际上不需要全局安装的事实,我想将其安装到用户的 $HOME/.bin 或 $HOME/local/bin (创建该如果没有现有的等价物)。
这是我当前的安装脚本:
#!/bin/bash
BASE="https://api.blah.com"
sudo bash -c "curl -s $BASE/mycmd > /usr/bin/mycmd"
sudo chmod uga+x /usr/bin/mycmd
我首先想到的是,许多用户现在都在使用 zsh。因此,如果我在 ~/.bashrc 中添加或修改一行来更新 PATH 以包含 $HOME/.bin,则这对这些系统不起作用。
所以重申一下这个问题,我应该使用什么代码来下载我的脚本并将其安装到该用户的 PATH($HOME/local/bin,或默认情况下 PATH 中可用的任何内容)目录中的用户可写目录中,并确保它位于他们的 PATH 中,并使用要求(或者至少是强烈的愿望)这将在几乎每个人的系统上工作(如果他们有类似 Unix 提示符的东西)(不需要 sudo)?
由于有些人认为修改 PATH 是邪恶的,所以我想安装在该系统的默认 $HOME/whatever/bin 中,如果可能的话,它已经在用户的 PATH 中,而不是自动修改他们的 PATH 以包含某些特定的路径目录。
非常感谢!
答案1
有一个词来形容将自身注入用户环境的程序:病毒。
只需安装到 ~/bin/ (手动安装脚本的历史事实上的标准)或 ~/.local/bin/ (由非根包管理器安装的脚本的现代、准形式标准)。通常,用户友好的发行版已经在 $PATH 中包含其中一个或两个。
或者更好的是,以交互方式提示用户输入安装前缀。
答案2
为什么不在脚本本身中查询 $PATH 呢?检查用户的 $PATH 中是否有可以写入的目录(通常为~/bin
或~/.local/bin
)。如果他们这样做,那就太好了,安装在那里。如果他们不这样做,那么你会提示。我相信,如果目录存在,某些发行版(例如 Ubuntu)会~/bin
自动添加到 $PATH,但你不能假设情况总是如此。
~/.profile
您唯一的选择是通过编辑由许多 shell 获取的目录将您安装的任何目录添加到 $PATH 中。忘记吧~/.bashrc
,它不仅是 bash 特定的,而且 $PATH 根本就没有必要在那里设置。然而,像这样编辑全局变量并不是一件好事。
最好的办法是检查可写目录,如果没有找到则提示。
答案3
管道到 sh 是有问题的,从安全的观点,更微妙的是,鲁棒性和错误处理观点看法。
如果您的安装脚本只有 3 行,为什么不让用户只执行这 3 行呢?他们已经在复制和粘贴您的curl
命令,并且将他们复制和粘贴的行做得更长一点,您可以这样做:
mkdir -p ~/bin && curl -s "https://api.blah.com/mycmd" > ~/bin/mycmd && chmod ugo+x ~/bin/mycmd
在大多数发行版上,只要目录存在,~/bin/
就会放入。$PATH
最坏的情况是,您的用户可能需要注销并重新登录才能将目录添加到他们的$PATH
.即使这不在他们的范围内$PATH
,你也可以告诉人们只要跑就可以~/bin/mycmd
了mycmd
。如果他们足够精通 Unix,他们就会知道他们可以确保它~/bin/
在他们的路径中,并删除多余的 6 个字符。如果他们不熟悉 Unix,并且他们的发行版没有帮助,他们必须额外输入 6 个字符 - 可能没什么大不了的。
如果有人拥有 root 权限并且想要安装在除 之外的其他地方~/bin/
,很容易更改上面的行来执行此操作 - 如果他们不明白如何进行更改,他们不应该更改根文件系统!
答案4
我最终在“入门”页面上给了他们两个选项。我简要解释安装程序脚本的作用,例如查找 ~/.local/bin 等,然后可能将其添加到 ~/.zshrc 或 ~/.bashrc 中的 PATH。我还为他们提供了手动安装的选项,而不是使用脚本,并提供了简单的说明。
要运行自动安装程序,用户可以粘贴并执行如下命令:
curl -s https://thesite.com/installmycmd > /tmp/inst; source /tmp/inst
这是 installmycmd 脚本:
#!/bin/bash
BASE="https://thesite.com"
declare -a binddirs
bindirs=($HOME/bin $HOME/.local/bin $HOME/.bin)
founddir="false"
findprofile() {
profiles=($HOME/.zshrc $HOME/.bashrc $HOME/.bash_login $HOME/.login $HOME/.profile)
for prof in "${profiles[@]}"; do
if [ -f "$prof" ]; then
echo "$prof"
return
fi
done
touch $HOME/.profile
echo "$HOME/.profile"
}
for bindir in "${bindirs[@]}"; do
if [ -d "$bindir" ]; then
founddir=true
echo "You have a user bin dir here $bindir."
whichprofile=$(findprofile)
pathline=$(grep ^PATH= $whichprofile)
if [[ ! $pathline == *$bindir* ]]; then
echo "Appending $bindir to PATH in $whichprofile"
echo -e "\nexport PATH=\$PATH:$bindir" >> "$whichprofile"
NEWPATH=$PATH:$bindir
export NEWPATH
else
echo "That is in your PATH in $whichprofile"
fi
break;
fi
done
if [ ! -z $NEWPATH ]; then
echo "Exported PATH: $NEWPATH"
export PATH=$NEWPATH
fi
if [[ "$founddir" == "false" ]]; then
echo "Could not find ~/.bin or ~/.local/bin or ~/bin."
echo "Creating ~/.local/bin and adding to PATH"
mkdir -p $HOME/.local/bin
bindir=$HOME/.local/bin
whichprofile=$(findprofile)
echo "Appending PATH edit to $whichprofile"
echo -e "\nexport PATH=$PATH:$HOME/.local/bin" >> "$whichprofile"
export PATH=$PATH:$HOME/.local/bin
fi
bash -c "curl -s $BASE/JSON.sh > $bindir/JSON.sh"
bash -c "curl -s $BASE/mycmd > $bindir/mycmd"
chmod ug+x $bindir/mycmd
chmod ug+x $bindir/JSON.sh