「ssh -t」でログインしてコマンドを実行できないのはなぜですか?

「ssh -t」でログインしてコマンドを実行できないのはなぜですか?

私はMac OS Big Surで仮想Ubuntu 16.04 Linuxインスタンス(vagrantを使用)を実行しています。次の2つのコマンドを正しく実行できます(1つは仮想サーバーにsshで接続し、2つ目はその中でコマンドを実行します)...

$ ssh myvirtual.local
Warning: Permanently added '10.0.4.19' (ECDSA) to the list of known hosts.
Last login: Wed Sep 15 16:37:57 2021 from 10.0.4.1
$ foreman start -f Procfile.debug
16:38:26 rails.1      | started with pid 27884
16:38:26 worker.1     | started with pid 27885
16:38:26 scheduler.1  | started with pid 27887
...

私はこれら2つのコマンドを組み合わせることができたかったので、試してみました。

$ ssh -t myvirtual.local 'foreman start -f Procfile.debug’
Warning: Permanently added '10.0.4.19' (ECDSA) to the list of known hosts.
bash: foreman: command not found
Connection to 10.0.4.19 closed.

単一のコマンドを使用して最初に実行した操作をシミュレートするために実行する必要がある他の設定が何であるかが混乱しています。どんなアイデアがありますか?

答え1

この場合の主な違いは、ssh hostログインモードでログインシェルを起動することです。接頭辞は、、、sshdまたは(おそらくシェルのシステム起動スクリプトからシステム起動スクリプトを読み取り、ログインセッションを初期化する必要があることをシェルに通知します。実装)および対話型(入力プロンプトを表示するため)。これがパターンです。-argv[0].profile.bash_profile.zprofile.zlogin.login/etcrloginssh

では、ssh -t host 'some shell code'引数を使用してログインシェルを実行しsshdますが、ログインシェルを指示しないでください。シェルも非対話型であり、端末からコードを求めるプロンプトを表示しません。これがパターンです。-csome shell codersh

あなたの場合、変数を設定するためのセッション初期化ファイルのいくつかの指示が$PATHまだ実行されていないため、コマンドが見つからない可能性があります。

すべてのシェルが同時にログインシェルとして機能し、引数として提供されたコードを解釈できるわけではありません。

ケースはbash大丈夫です。起動時にログインシェルで始まり、bashまたはオプションが渡されると、実行コマンドが渡されても、1はまだログインしているセッション初期化ファイルを読み取ります(POSIXモードを除く)。argv[0]--l--login-c

したがって、これを行うのではなく、次のようにします。

ssh -t host 'some code'

次のことができます。

ssh -t host "exec bash --login -c 'some code'"

これは別のことを始めますbashが、今回は解釈する前にログインシェルとして使用されます(その中のコード~/.bash_profileと初期化がある場所を解釈します/etc/profile)。/etc/profile.d$PATHsome code

または、定義が作成されたファイルを見つけて、$PATH次のことを実行できます。

ssh -t host '. /path/to/that/file && some code'

これはまだ別の違いを残します。つまり、シェルはインタラクティブではなく、起動ファイルはインタラクティブの場合と非インタラクティブのときに異なる動作をすることができます(存在するかどうかを確認するか、i変数$-が存在するかどうかを確認して$PS1)。

bashログインシェルとして実行すると~/.bashrc(他のほとんどのシェルで発生するのとは対照的に)起動時に(対話型シェルカスタムファイル)は解釈されませんが、ほとんどの人はDebianとその派生製品source ~/.bashrcでそれを使用します。~/.bash_profileバージョンは~/.profileデフォルトでこれを行います(もちろんシェルがある場合のみbash)。

bashこれはsshを介して呼び出されるとデフォルトでは解釈されませんが、設定~/.bashrcオプションを使用してコンパイル時に設定できますSSH_SOURCE_BASHRC。 DebianやUbuntuなどの派生製品がこれを可能にします。したがって、これを行うときにssh ubuntu-host 'some code'ログインシェルがそのマシンでbashの場合、実行されるシェルが解釈されるbash前にsshd解釈されます。~/.bashrcsome code

したがって、最終的にはモードの内外と~/.bashrc解釈されますが、@Quasimodoが指摘したように、DebianとUbuntuのデフォルトは一番上にあります。rloginrsh~/.bashrc

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

$PATHしたがって、この行の下に定義がある場合、モードrloginbashインタラクティブ、インクルード、および$-ソースi~/.bashrcある場合)でのみ解釈され、モード(ソースがあるがその内容の大部分をスキップする場合)~/.profileでは解釈されません。シェルはインタラクティブではありません。)rsh~/.bashrc


1 (/ とは逆) で始まる場合argv[0]a 転送がログインシェルとして処理されるかどうかは、コンパイルが有効かどうかによって異なります。--l--login-c codebashNON_INTERACTIVE_LOGIN_SHELLS

答え2

2つのケースが常に同じではないため、環境設定がありません。

ssh remoteHost
someCommand

ssh -t remoteHost someCommand

次のコマンドブロックは、好ましい解決策から欠落している変数のセットを提供します(上記の2つの例の2番目の形式)。これらの内容を質問に追加すると、設定方法を説明する質問を完了したり、この情報を使用して直接設定したりできます。

ssh -t myvirtual.local env | grep = | sort >/tmp/env.1
( echo env; echo exit ) | ssh -tt myvirtual.local | grep = | sort >/tmp/env.2
comm -13 /tmp/env.1 /tmp/env.2

私のシステムの簡単な出力例はここにあります。

EDITOR=vi
HISTCONTROL=ignoredups
LESSCLOSE=/usr/bin/lesspipe %s %s
LESSOPEN=| /usr/bin/lesspipe %s
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:...
PAGER=less
PATH=/home/roaima/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/bin:/bin
PROMPT_COMMAND_WAS=echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"
SHLVL=1
SSH_CLIENT=192.1.1.9 31996 22
SSH_CONNECTION=192.1.1.9 31996 192.1.1.18 22
TTY=/dev/pts/0
XDG_SESSION_ID=c61

これはRubyやRailsに固有のものではありませんが、私の場合は変数が異なることを示しています(そして実際の値を見ることができますPATH)。/tmp/env.1/tmp/env.2

これを追跡してソートした後は、接続が終了したときに信号を受信しないようにするか、foreman以下で実行することをお勧めします。ただし、これらの追加ツールを導入する前に、初期の問題を解決することをお勧めします。screentmuxSIGHUPssh

関連情報