测试(在 Ubuntu 上)

测试(在 Ubuntu 上)

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

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

$ echo $PATH
/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

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

$ ssh <user>@<ip> 'echo $PATH'
/usr/local/bin:/usr/bin:/bin:/usr/games

答案1

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

$ ssh localhost 'echo $- $0; shopt login_shell'
hBc bash
login_shell     off

$ ssh localhost
[terdon@tpad ~]$ echo $- $0; shopt login_shell
himBHs -bash
login_shell     on

这个答案了解这实际上向您展示的内容的详细信息。

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

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

例如,当 bash 以非交互方式启动时,要运行 shell 脚本,它会在环境中查找变量 BASH_ENV,如果出现则扩展其值,并使用扩展后的值作为要读取的文件名并执行。 Bash 的行为就像执行了以下命令:

    if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

但 PATH 变量的值不用于搜索文件名。

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

所以,你的选择是:

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

    ssh ip /home/linuxbrew/.linuxbrew/bin/pyenv
    
  2. 来源~/.profile

    ssh ip '. ~/.profile; pyenv'
    

答案2

您的诊断可能是正确的。

为了避免这个问题,你需要验证哪个rcfile是不是在启动时执行(它可能是设置 PATH 的脚本),在您引用的答案中的脚本中。

然后,您可以重写~/.bashrc以避免该问题。

或者您可以尝试更改命令:

ssh <user>@<ip> '. /etc/profile; pyenv versions'.

这将导入/etc/profile到当前执行的 shell 中。您可能需要导入/etc/bashrcor~/.profile代替/etc/profile, 或点它们(注意点和文件名之间有一个空格;此外,整个命令都被引用)。

测试(在 Ubuntu 上)

登录方便的虚拟机:

leonardo@aladdin:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/opt/android-sdk-linux/platform-tools:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
leonardo@aladdin:~$ logout

现在尝试直接使用 SSH:

$ ssh leonardo@aladdin "echo \$PATH"
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

好的。所以,不同的路径。例如,java-8-oracle 从哪里来?您将进行一些类似的检查,在 PATH 中使用一些长字符串,该字符串仅在登录 shell 中时才存在

作为虚拟机的 root,我在 PATH 分配之后的各处查找该字符串/etc(如果它不起作用,我将通过指定 来重试主点文件/home/.*)。

# grep -r PATH.*java-8-oracle /etc
/etc/profile.d/jdk.csh:setenv PATH ${PATH}:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
/etc/profile.d/jdk.sh:export PATH=$PATH:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin

PATH 分配就在那里,显而易见。

它来自“/etc/profile.d”中的一个文件。现在需要一些琐事 - 知道“whatever.d”文件夹是通常从任何二进制文件,并且它们的内容按顺序进行通配。

因此,如果该文件夹是/etc/profile.d,我希望这个技巧能够被实现/etc/profile。无论如何,必须有人干预“profile.d”,所以我可以寻找

# grep -r "profile\.d" /etc

事实上,我在几行输出中发现:

/etc/bash_completion.d/libreoffice.sh:# It is based on /etc/profile.d/complete.bash from SUSE Linux 10.1
/etc/profile:if [ -d /etc/profile.d ]; then
/etc/profile:  for i in /etc/profile.d/*.sh; do
/etc/apparmor.d/snap/abstractions/bash:  /etc/profile.dos                 r,
...

第二行和第三行是我感兴趣的。他们说,“如果有一个名为 /etc/profile.d 的文件夹,那么;对于该文件夹中以“.sh”结尾的每个文件,执行...” 。这是确切地这是我所期望的。

所以,我可以相信跑步/etc/profile会起到作用。

确实有效:

ssh leonardo@aladdin ". /etc/profile; echo \$PATH"
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/opt/android-sdk-linux/platform-tools:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin

相关内容