heredocを使用してリモートサーバーでwhileループを実行する

heredocを使用してリモートサーバーでwhileループを実行する

リモートコンピュータで以下のスクリプトを実行しようとしましたが、ここで2つの問題に直面しました。

  1. ここでドキュメントで定義されているwhileループは無限に実行されます。
  2. 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 lineread -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(引用符は同様のシェルにのみ有害です)。zshfishexec bash -c -- $LC_CODErccshtcshexec 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-+bashps -Awww


¹この場合はそうですsshdbash -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"

関連情報