私のスクリプトがループを終了するのはなぜですか?

私のスクリプトがループを終了するのはなぜですか?

私のスクリプトが最初の行の後にループを出る理由を理解できません。 deleteUser関数内で別のスクリプトを呼び出しているため、動作が中断されるようです。

以下は私のスクリプトから抜粋したものです。

[...]

function deleteUser
{
  nfsserver="/local/scripts/find_home_in_nfs.sh ${1}"
  ssh -n $nfsserver "rm -rf /home/${1}"
  ssh ldap "sudo deleteUser ${1}"
  userHome ${1}
}

cat myFile | while read line
do
  username=`echo ${line} | awk -F" " '{print $1}'`
  action=`echo ${line} | awk -F" " '{print $2}'`

  if [ "${action}" == "d" ]; then
     deleteUser ${username}
  elif [ "${action}" == "a" ]; then
     addUser ${username}
  fi
done

"find_home_in_nfs.sh"(ホームの場所を見つけるためにすべてのNFSサーバーへの多くのSSH接続を実行します)を呼び出さずにスクリプトの単純化されたバージョンを再構築してみましたが、うまくいきました。

ただし、使用する必要がありますが変更できません。 whileループを操作する方法はありますか?

答え1

次の例のように、ループを大幅に簡素化できます。

while read username action
do
   if [ "${action}" == "d" ]; then
      echo "deleteUser ${username}"
   elif [ "${action}" == "a" ]; then
      echo "addUser ${username}"
   fi
done < myFile

答え2

基本的な問題は、sshほとんどのファイルを読むことです。read lineファイルから最初の行を読み、次に(他の何よりも)stdinで未読実行を実行し、次にssh -n $nfsserver "rm -rf /home/${1}"stdinで読み取らずに-n実行するので、内容を読み取ることができるすべての内容(つまり、ファイル全体の残りの部分)を読みます。リモートコンピュータに送信すると無視されます。その後、次の反復が開始され、ファイルから読み取ろうとしますが、最後にあるのでループが終了します。ssh ldap "sudo deleteUser ${1}"-nread line

-n追加のコマンド(および実行できるssh他のコマンド)を追加することで、この問題を解決できます。sshそしてstdinで読むことができる他のすべてのコマンドに似たものを追加します</dev/null。しかし、私は完全な混乱をスキップするためにstdin以外のコマンドから読み取るファイルを送信することを好みます。 FD#3を使用して送信および読み取る方法は次のとおりです。

while read line <&3; do
    ...
done 3<myFile

readこれをフィールド分割を処理する@fpmurphy1の提案と@Kusalanandaの次の使用と組み合わせますcase

while read username action <&3
do
   case "$action" in
       d) deleteUser "$username" ;;
       a) addUser "$username" ;;
       *) echo "Unknown action: $action on user $username" >&2 ;;
   esac
done 3< myFile

ところで、一度に多数のユーザーを追加および削除する場合は、さらに最適化したいと思います。現在のバージョンでは、各サーバーで各ユーザーに対して別々のSSHセッションを開きます。各サーバーへの単一の接続を開き、その接続を介してすべてのユーザーを処理する方が高速です。欠点:注意しないと、エラー処理がより複雑になる可能性があります。

答え3

bash連想配列を使用するより簡単なコード:

declare -A a=([a]=add [d]=delete)
while read username action; do
    ${a[$action]}User ${username}
done < myFile

関連情報