Bash

SSH 進入 VM 和從腳本執行 SSH 命令之間的不同行為

  • May 20, 2022

我對 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)"

我還意識到,如果我從我的 VM 中查看我的路徑,它看起來像這樣:

$ 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

當你 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/profile讀取並執行命令(如果該文件存在)。讀取該文件後,它會按順序查找~/.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
  1. 來源~/.profile
ssh ip '. ~/.profile; pyenv'

引用自:https://unix.stackexchange.com/questions/703147