我应该使用什么代码来下载脚本并将其安装到用户 PATH 中的用户可写目录中(不需要 sudo)?

我应该使用什么代码来下载脚本并将其安装到用户 PATH 中的用户可写目录中(不需要 sudo)?

编辑:我说 $HOME/.bin 的地方我应该写 $HOME/bin 或任何等效的东西都可以。 IE,用户 PATH 中的任何用户可写目录。

所以我有一个 bash 脚本,我将其作为 API 的客户端进行分发。当前版本安装如下curl -s http://api.blah.com/install | sudo sh。我可能会尝试处理六个不同的包管理系统,以便它们可以仅apt-getbrew 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/mycmdmycmd。如果他们足够精通 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

相关内容