偽Aターミナル

偽Aターミナル

非常に似ています.bashrcを取得したら、sshを使用して対話型シェルでコマンドを実行します。しかし、そこへの答えは私には役に立ちませんでした。

完全なインタラクティブシェルからSSHを介してリモートコマンドを実行したいと思います。つまり、
ログインシェルでいくつかのパラメータを使用してリモートコマンドを実行します。

デフォルトで動作するには、次の2つが必要です。

ssh user@remote_computer -t bash -l -c '/bin/echo PATH is $PATH'
ssh user@remote_computer -t 'bash -l -c "java -version"'

java: command not foundただし、現在のケース1とケース2に空白行が表示されます。

$ ssh user@remote_computer -t bash -l -c '/bin/echo PATH is $PATH'

Connection to remote_computer closed.

$ ssh user@remote_computer -t bash -l -c 'true; /bin/echo PATH is $PATH'
PATH is /usr/local/bin:/usr/bin:/bin:/usr/games
Connection to remote_computer closed.

ssh user@remote_computer -t bash -l -c 'true; java -version'
bash: line 1: java: command not found
Connection to remote_computer closed.

修正する:

少なくとも二人はこれが引用問題だと思いますが、これが引用問題である理由と上記で望むものをどのように得ることができるかを説明してもらえますか?たとえば、私が試したことは次のとおりです。

ssh user@remote_computer -t 'bash -l -c "java -version"'
bash: line 1: java: command not found
Connection to remote_computer closed.

私はそれを別の方法で参照する方法をすでに知りません。助けてください!

後で同じコマンドを実行すると、次の結果ssh user@remote_computerが表示されます。

$ bash -l -c "java -version"
openjdk version "11.0.15" 2022-04-19 LTS
OpenJDK Runtime Environment Zulu11.56+19-CA (build 11.0.15+10-LTS)
OpenJDK 64-Bit Server VM Zulu11.56+19-CA (build 11.0.15+10-LTS, mixed mode)

したがって、これは明らかに私に引用の問題ではありません。

ベストアンサー1

-cSSH経由のシェルコマンドはここで問題があります。いくつかのトリッキーな引用問題があり、誰が何を実行しているのか分かりません。テスト目的でここでcustomjava読んだ内容だけが知られています。~/.bashrcZSHは私のデフォルトのシェルです。

$ ssh -t localhost bash -c 'source ~/.bashrc;customjava -version'
/home/jhqdoe/.bashrc: line 0: source: filename argument required
source: usage: source filename [arguments]
zsh:1: command not found: customjava
Connection to 127.0.0.1 closed.
$ ssh -t localhost bash -c ':;source ~/.bashrc;customjava -version'
java version 99999
Connection to 127.0.0.1 closed.

上記の2つのコマンド間の違いを理解するために、いくつかのことをstrace行い、ソースコードを詳しく見ることができると思います(空のコマンドであり、実際よりも入力が少ない)。しかし、すでに脆弱でデバッグが難しい場合は、別の解決策を探してみましょう。私が好むのは、通常、コマンド全体を引用することです。ssh -v -v -v:true

$ ssh localhost 'bash -ic "customjava -version"'
java version 99999

ただし、より複雑な引用要件と変数置換がコマンドに含まれる場合、これは複雑すぎる可能性があります。 (複雑なシェル引用符は夜明け2時にデバッグしたいものではないので、基本的に避ける傾向があります。)

パイプの代わりに

別の方法は、コマンドを目的のシェルにパイプすることです。これにより、コマンド実行の複雑さが最小限に抑えられ、オプションのシェル呼び出しが可能になります。

$ printf 'customjava -version'"\n" | ssh localhost 'bash -i'
bash$ customjava -version
java version 99999
bash$ exit
$ printf 'customjava -version'"\n" | ssh localhost 'bash -l'
java version 99999

ここでの欠点は、標準入力が端末ではないため、相手のコマンドに端末が必要な場合は機能しないことです。これに警告がある可能性があります。

$ printf 'customjava -version'"\n" | ssh localhost
Pseudo-terminal will not be allocated because stdin is not a terminal.
zsh: command not found: customjava
$ printf 'customjava -version'"\n" | ssh -t localhost
Pseudo-terminal will not be allocated because stdin is not a terminal.
zsh: command not found: customjava

偽Aターミナル

端末が必要な場合は、おそらくに切り替えますexpect。これにより、コマンドが実行される偽の端末が生成されます。

#!/usr/bin/env expect

spawn -noecho ssh localhost

# assume a prompt containing at least "% " (ZSH)
expect "% "

# replace ZSH with another shell
send -- "exec bash\n"
# assume a prompt of at least "$ "
expect "$ "
send -- "customjava -version\n"
expect "$ "
set version_info $expect_out(buffer)
send -- "exit\n"

puts "got >>>$version_info<<<"

しかし、特にエラーチェックとシェルプロンプトの検出に関連する他の問題があります(たとえば、誰かがそれを操作している可能性があるため、最初にすべきことは、プロンプトを既知の値と一致するように expect設定することです)。誰かがさまざまな方法の1つでインタラクティブシェル構成を破損した場合でも、競合が発生する可能性があります。たぶん走り /bin/shたくないですかbash?ただし、shカスタムJavaを設定する必要があるかもしれません。これにより...

シェルから構成を削除する

この問題を解決する別の方法は、環境を正しく構成するSSHサーバーに特別なコマンド(例:execラッパー)を作成してから、そのコマンドまたは他のjavaコマンドを実行することです。その後、setup-our-env bash(ユーザーが使用できる対話型シェル)または setup-our-env java -version(対話型シェルの複雑さなしにSSHを介して実行される簡単なコマンド)を実行できます。 Execラッパーは次のように簡単にできます。

#!/bin/sh
PATH=/custom/java/bin:$PATH
exec "$@"

つまり、カスタムJavaバージョンの環境設定はインタラクティブシェル構成と完全に混在しないため、必要なコマンドに適用できます。

おすすめ記事