SSH 進入 VM 和從腳本執行 SSH 命令之間的不同行為
我對 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
命令已添加到您的$PATH
in 中/home/f0p021s/.profile
。正如您在上面看到的,該文件 (~/.profile
) 由互動式登錄 shell 讀取,而不是由非互動式或非登錄 shell 讀取,因為它們只讀取指向的$BASH_ENV
內容,預設情況下為空。因此,您的選擇是:
- 只需使用命令的完整路徑:
ssh ip /home/linuxbrew/.linuxbrew/bin/pyenv
- 來源
~/.profile
:ssh ip '. ~/.profile; pyenv'