通过 SSH 进入虚拟机和从脚本运行 SSH 命令之间的不同行为

Fra*_*nto 5 bash ssh debian

我对 shell 脚本编写比较陌生,所以如果这看起来是一个简单的问题,我深表歉意。我有一个 Linux VM ( debian, version 11 (bullseye)),我可以通过 ssh 进入 ( ssh <ip>),安装了一些依赖项(homebrew、pyenv 等),并且能够成功使用它们。ssh <user>@<ip> pyenv versions但是,当我尝试在脚本中或使用 Mac 终端从 VM ( ) 外部运行命令时,会收到bash: line 1: pyenv: command not found相关错误。

我认为这可能与此处解释的内容有关,但我不完全确定如何规避该问题。

在下面的评论中添加@terdon 询问的其他详细信息:

$ which pyenv
/home/linuxbrew/.linuxbrew/bin/pyenv

$ grep /home/linuxbrew/.linuxbrew/bin/ ~/.bashrc ~/.bash_profile ~/.profile /etc/bash.bashrc /etc/profile
grep: /home/f0p021s/.bash_profile: No such file or directory
/home/f0p021s/.profile:eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
Run Code Online (Sandbox Code Playgroud)

我还意识到,如果我从虚拟机中查看路径,它看起来像这样:

$ echo $PATH
/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
Run Code Online (Sandbox Code Playgroud)

当我尝试从本地计算机运行类似的命令时,它看起来有所不同:

$ ssh <user>@<ip> 'echo $PATH'
/usr/local/bin:/usr/bin:/bin:/usr/games
Run Code Online (Sandbox Code Playgroud)

ter*_*don 11

当您 ssh 进入计算机时,您将启动交互式登录 shell。当你跑步时ssh ip command,您将启动一个非交互式、非登录 shell:

\n
$ ssh localhost \'echo $- $0; shopt login_shell\'\nhBc bash\nlogin_shell     off\n\n$ ssh localhost\n[terdon@tpad ~]$ echo $- $0; shopt login_shell\nhimBHs -bash\nlogin_shell     on\n
Run Code Online (Sandbox Code Playgroud)\n

请参阅此答案,详细了解这实际上向您展示了什么。

\n

每种类型的 shell 在启动时读取的文件都不同。来自man bash (强调我的):

\n
\n

当 bash 作为交互式登录 shell或带有 --login 选项的非交互式 shell被调用时,它首先从文件/etc/profile中读取并执行命令(如果该文件存在)。读取该文件后,它会按照该顺序查找 ~/.bash_profile、~/.bash_login 和 ~/.profile,并从第一个存在且可读的文件中读取并执行命令。启动 shell 时可以使用 --noprofile 选项来禁止此行为。

\n
\n
\n

当 bash 以非交互方式启动时,要运行 shell 脚本,对于 ex\xe2\x80\x90\nample,它会在环境中查找变量 BASH_ENV,如果出现在那里,则扩展\nits 值,并将扩展后的值用作要读取和执行的文件的\n名称。Bash 的行为就像执行了以下 com\xe2\x80\x90\nmand :

\n
    if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi\n
Run Code Online (Sandbox Code Playgroud)\n

但 PATH 变量的值不用于搜索文件\xe2\x80\x90\nname。

\n
\n

现在,您已经向我们展示了该pyenv命令已添加到您的$PATHin 中/home/f0p021s/.profile。正如您在上面所看到的,该文件 ( ~/.profile) 由交互式登录 shell 读取,但不会由非交互式或非登录 shell 读取,因为这些文件仅读取 指向的内容$BASH_ENV,并且默认情况下为空。

\n

所以,你的选择是:

\n
    \n
  1. 只需使用命令的完整路径:

    \n
    ssh ip /home/linuxbrew/.linuxbrew/bin/pyenv\n
    Run Code Online (Sandbox Code Playgroud)\n
  2. \n
  3. 来源~/.profile

    \n
    ssh ip \'. ~/.profile; pyenv\'\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
\n