私はシェルスクリプティングに比較的慣れていないので、これが簡単な質問のように思えば謝罪します。私はdebian, version 11 (bullseye)
SSHを介して()に接続できるLinux VM()を持っており、ssh <ip>
いくつかの依存関係(homebrew、pyenvなど)をインストールして正常に使用できます。ただし、VMの外部(スクリプトまたはMac端末を使用)でコマンドを実行しようとすると、関連するエラーが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接続すると、対話型ログインシェルが起動します。を実行すると、ssh ip command
非対話型の非ログインシェルが起動します。
$ 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
バラよりこの回答これが実際に何を示しているかを学びましょう。
各タイプのシェルは起動時に異なるファイルを読み込みます。man bash
(ハイライト内)から:
bashを次のように使用するとき対話型ログインシェルまたは --login オプションを使用して最初にファイルから読み込み、コマンドを実行する非対話型シェルとして使用する/etc/設定ファイル、ファイルが存在する場合。ファイルを読み込んで見つけます。~/.bash_profile、~/.bash_login、~/.profileの順に、最初の既存および読み取り可能なコマンドからコマンドを読み取り、実行します。この動作は、シェルの起動時に --noprofile オプションを使用して無効にできます。
たとえば、bashが非対話型で起動されたときにシェルスクリプトを実行するには、環境でBASH_ENV変数を探し、その値がある場合は展開し、拡張値を読み取り、実行するファイル名として使用します。 Bashは、次のコマンドが実行されたかのように動作します。
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
ただし、PATH変数の値はファイル名を取得するためには使用されません。
これで、コマンドがinpyenv
に追加されたことがわかりました。上記のように、ファイル()は対話型ログインシェルから読み取られますが、非対話型または非ログインシェルでは読み取られません。なぜなら、これらのファイルは指定された内容だけを読み込み、デフォルトで空であるからです。$PATH
/home/f0p021s/.profile
~/.profile
$BASH_ENV
したがって、あなたのオプションは次のとおりです。
コマンドのフルパスを使用します。
ssh ip /home/linuxbrew/.linuxbrew/bin/pyenv
源泉
~/.profile
:ssh ip '. ~/.profile; pyenv'
答え2
あなたの診断が正しいかもしれません。
この問題を回避するには、どのrcfileが存在するかを確認する必要があります。いいえ引用した回答のスクリプトで起動時に実行されます(おそらくPATHを設定するスクリプトです)。
~/.bashrc
その後、上書きして問題を回避できます。
または、次のコマンドを変更してみることもできます。
ssh <user>@<ip> '. /etc/profile; pyenv versions'.
/etc/profile
これは現在実行中のシェルにインポートされます。/etc/bashrc
をインポート、置換~/.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の長い文字列を使用して、同様のチェックを実行します。。
仮想マシンのルートとして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,
...
2行目と3行目は、私が興味を持っている部分です。彼らは、「/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