![ssh経由でコマンドを実行できない](https://rvso.com/image/1711437/ssh%E7%B5%8C%E7%94%B1%E3%81%A7%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84.png)
FreeBSDマシン(xxx.yyy.zzz.net)でコマンドを実行し、出力を取得しています。
指示
sudo camcontrol devlist | grep -o 'ada[0-9]' | while read -r a ; do sudo camcontrol identify $a | grep rotating ; done
出力
media RPM non-rotating
media RPM non-rotating
media RPM non-rotating
別のマシンからsshを使用して同じコマンドを実行しようとしています
指示
ssh xxx.yyy.zzz.net sudo camcontrol devlist | grep -o 'ada[0-9]' | while read -r a ; do sudo camcontrol identify $a | grep rotating ; done
エラー
sudo: camcontrol: command not found
答え1
コマンドでは、すべてが|
ローカル シェルによって解釈されます。最後の引数ssh
は ですdevlist
。ssh
はローカルで呼び出されます (これは驚くことではありません)。ただし、最初の の後のすべてのものも同様です|
。
発生したエラーはsudo
次のスニペットから発生しました: do sudo camcontrol identify $a
。これはローカルで実行され、どうやらcamcontrol
ローカル マシンでは利用できないようです。
適切なエスケープまたは引用符が必要です。この場合、リモート コマンド全体を一重引用符で囲む必要があります。
ssh xxx.yyy.zzz.net 'sudo camcontrol devlist | grep -o "ada[0-9]" | while read -r a ; do sudo camcontrol identify $a | grep rotating ; done'
すでにある一重引用符を変更したことに注意してください。(追加された)一重引用符は、文字列全体をグループ化してssh
取得するだけでなく、 のローカル展開も防止します$a
。
sudo
がパスワードを尋ねる場合、擬似端末が必要になります。-t
のオプションを使用して擬似端末の割り当てを強制することができますssh
(つまり のようになりますssh -t xxx.yyy.zzz.net …
)。ssh -t
はリモート側に擬似端末を割り当てることに注意してください。リモートはsudo
stderr にプロンプトを表示しますが、その後 stdout と stderr がこの擬似端末によって「出力」され (通常コンソールに出力されるのと同じように)、この時点ではこれらを区別できなくなります。マージされたストリームがキャプチャされ、ローカル側に転送されて stdout に送られます。 がない場合、-t
リモートの stdout と stderr は別々に転送され、ローカル側の stdout と stderr に移動し、最終的にこれらがマージされて (リダイレクトされている場合はマージされずに) 表示されます。つまり、 では-t
(ローカル側で) リモートの stderr とリモートの stdout を区別できません。出力をさらにローカルで処理 (リダイレクト) する必要があり、 を使用する場合、-t
からのプロンプトsudo
は干渉します。
また、おそらく二重引用符を使用する必要があるでしょう$a
( を使用しない最初のコマンドでもssh
)。シェル スクリプトが空白文字やその他の特殊文字で動作しなくなるのはなぜですか?