テスト(Ubuntuから)

テスト(Ubuntuから)

私はシェルスクリプティングに比較的慣れていないので、これが簡単な質問のように思えば謝罪します。私は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

したがって、あなたのオプションは次のとおりです。

  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これは現在実行中のシェルにインポートされます。/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

関連情報