リモートコンピュータで以下のスクリプトを実行しようとしましたが、ここで2つの問題に直面しました。
- ここでドキュメントで定義されているwhileループは無限に実行されます。
- Enterキーの読み取りがリモートホストで機能しない
スクリプトはsshpassコマンドなしでlocalhostで正しく機能します。
誰かがこの問題を調査して助けることができますか?
1 #!/bin/bash
2 #read -p "Enter the user name to connect to server: " user
3 #read -s -p "Enter the password : " passd
4 #sshpass -p $passd ssh -qt -o StrictHostKeyChecking=no -o ConnectTimeout=4 $user@$1 << 'MYSCR'
5 ##############################################################################################################################################
6 while :
7 do
8 clear
9 echo "Server Name - $(hostname)"
10 echo "1. Check Server Information"
11 echo "2. Check Network Information"
12 echo "q. to Exit"
13 read -p "Enter your choice [ 1 - 3 ]" choice
14 case $choice in
15 1)
16 echo "Server Date : `date`"
17 echo "Server Uptime :`uptime`"
18 read -p "Press [Enter] key to continue..."
19 readEnterKey
20 ;;
21 2)
22 echo "File system information"
23 df -hP | column -t
24 read -p "Press [Enter] key to continue..."
25 readEnterKey
26 ;;
27 q)
28 echo "Bye!"
29 exit 0
30 ;;
31 *)
32 echo "Error: Invalid option..."
33 read -p "Press [Enter] key to continue..."
34 readEnterKey
35 ;;
36 esac
37 done
38 #MYSCR
答え1
いくつかの問題:
一行を読むとです
IFS= read -r line
。read -s -p "Enter the password : " passd
特に、パスワードにバックスラッシュが含まれているユーザー、または文字で始まるか終わるユーザーの場合は機能しません$IFS
。だからそうしなければならないIFS= read -rsp 'Enter the password: ' passd || exit
Bashでは、リストコンテキストのパラメータ拡張を引用する必要があります。
"$user@$1"
、$user@$1
例ではありません。-o StrictHostKeyChecking=no
ちょっとそうだと思います。私を壊してください。ネットワークを完全に信頼できない場合、クライアントに対してサーバーを認証することは、サーバーに対してクライアントを認証するのと同じくらい重要です。ディレクティブは次のとおりです。「身元証明を要求せずに、ユーザーは自分が誰であるかを信頼します。」サーバー側で完了したら。パスワードおよびその他の秘密情報はシステム内の公開情報であるため、コマンドパラメータに渡してはいけません。マニュアル
sshpass
ページにはこれに関する大きな警告があります。SSHPASS="$passd" sshpass -e ssh...
パスワード認証よりも優れた形式の認証を使用するか、引き続き使用することをお勧めします。unset
変数にシークレットデータを保存させる前に、その変数が環境にエクスポートされないように処理することをお勧めします(コマンドで漏れ、それ自体でさらに漏洩する可能性があります。ここではそうではありません。条件)。 Bashではunset -v passd
。を使用すると、
sshpass ... ssh ... << 'HEREDOC'
文書がリモートコマンドにsshpass
渡される標準入力になります。ssh
ここでは実行したいコマンドを指定しないので、それは何でもリモートユーザーのログインシェルになります。stdinはターミナルデバイスではないので、リモート側に疑似ターミナルを作成しないように
ssh
要求します。それ以外の場合は、プロンプトをエコーし、対話型シェルの実行を開始します。スクリプトが実行されたときにやりたいこと。sshd
-t
そのため、シェルは標準入力で実行されるコードを読み込みます。
ただし、そのコードは標準入力でも読み取られます。は
read -p "Enter your choice [ 1 - 3 ]" choice
この定理で読まれます。ありがたいことread
に、シェルがループ全体のコードを読み取るまで実行されないため、ここでドキュメントの後にあるwhile
ものだけを読むか、後に何もない場合は何も読み込み、eofから失敗を返します。
bash
ここでは、ユーザーのログインシェル(bashをログインシェルとして使用する人は誰ですか?:-b)ではなく、リモートホストでシェルを実行する必要があります(bash固有の構文を使用するため)。非対話型で実行し、コードを渡します。 stdinを取ることに加えて別の方法で。AcceptEnv LC_*
SSHサーバー構成にいくつかの一般的な構成がある場合は、次のことができます。
code=$(
cat <<'EOF'
the code there
EOF
)
それから:
SSHPASS="$passd" LC_CODE="$code" sshpass -e ssh -o SendEnv=LC_CODE -qt "$user@$1" '
exec bash -c -- "$LC_CODE"'
これは、リモートホストのログインシェルが変数を引用する$user
構文を理解し、$var
引用に二重引用符を使用できることを前提としています(Bourneなどのシェルでは分割+グローブを避けるために必要です)。ログインシェルがorまたはの派生であれば十分ですrc
(引用符は同様のシェルにのみ有害です)。zsh
fish
exec bash -c -- $LC_CODE
rc
csh
tcsh
exec bash -c -- $LC_CODE:q
それを書いてください:
SSHPASS="$passd" LC_CODE="$code" sshpass -e ssh -o SendEnv=LC_CODE -qt "$user@$1" '
exec bash -c '\''eval -- "$LC_CODE"'\'
これは、ユーザーのログインシェルが上記のいずれかである場合に機能します。これは、少なくともbash -c 'eval -- "$LC_CODE"'
すべてのBourneのような、rcのような、cshのような、フィッシュシェルが同じコードを理解しているからです。ps -Awww
このコードがリモートホストの出力に公開されないという利点もあります。
以下で詳しく学ぶことができます。リモートユーザーのログインシェルを知らず、SSHを介して任意の単純なコマンドをどのように実行できますか?
SSHPASS="$passd" sshpass -e ssh -qt "$user@$1" " $code"
@aviroの答え(またはで始まる場合に必要な追加スペースを追加する$code
)は、ユーザーのログインシェルです。また、ローカルシステムとリモートシステムの両方の出力にコードが公開されることに注意してください。$code
-
+
bash
ps -Awww
¹この場合はそうですsshd
。bash -c thatcode
そして、少なくとも現在のバージョンのopensshはこれを行いませんbash -c -- thatcode
(おそらくすべてのシェルがそれをサポートまたは要求しないため、--
または問題のために(実際にはあまり発生しない可能性があります)、無視されます)。C言語にも同じ問題がありますsystem()
数十年間放置された)
答え2
この文書では、テキストが標準入力(標準入力)プロセス、この場合 -標準入力あなたのssh
プロセス。このドキュメントを次にリダイレクトしたため標準入力あなたのssh
キーボードを読むことができません。
中ではなく標準入力sshを使用して変数に割り当て、その変数をssh
コマンドとしてリモートホストで実行します。
# Read the here-document into the $COMMAND variable
read -r -d '' COMMAND << 'MYSCR'
while :
do
clear
...
MYSCR
# Run ssh with $COMMAND
sshpass -p $passd ssh -qt -o StrictHostKeyChecking=no -o ConnectTimeout=4 $user@$1 "$COMMAND"