while loop stops after first iteration - remote ssh exit command problem?

I have written the following script to update some Debian boxes.

#!/bin/bash

mxg_hosts_file="/etc/mxg/ssh-hosts"

while read line ; do
    mxg_host="$(echo ${line} | awk -F":" '{print $1}')"
    mxg_port="$(echo ${line} | awk -F":" '{print $2}')"
    echo "Connecting and Upgrading ${mxg_host}"
    ssh root@${mxg_host} -p ${mxg_port} 'aptitude update && aptitude safe-upgrade -y && reboot && exit'
done < ${mxg_hosts_file}
> cat /etc/mxg/ssh-hosts
mx.example1.com:2225
mail.example2.com:22
mail.example3.com:222

The while loops stops after the first loop - it almost seems like the exit in the remote ssh command is being interpreted by the while loop, but I am not sure.

> bash -xv /usr/local/bin/updatemxg.sh
#!/bin/bash

mxg_hosts_file="/etc/mxg/ssh-hosts"
+ mxg_hosts_file=/etc/mxg/ssh-hosts
#mxg_hosts_file="/etc/mxg/ssh-hosts.test"

while read line ; do
    mxg_host="$(echo ${line} | awk -F":" '{print $1}')"
    mxg_port="$(echo ${line} | awk -F":" '{print $2}')"
        echo "Connecting and Upgrading ${mxg_host}"
        ssh root@${mxg_host} -p ${mxg_port} 'aptitude update && aptitude safe-upgrade -y && reboot && exit'
done < ${mxg_hosts_file}
+ read line
echo ${line} | awk -F":" '{print $1}')"
echo ${line} | awk -F":" '{print $1}')
echo ${line} | awk -F":" '{print $1}'
++ awk -F: '{print $1}'
++ echo mx.example1.com:2225
+ mxg_host=mx.example1.com
echo ${line} | awk -F":" '{print $2}')"
echo ${line} | awk -F":" '{print $2}')
echo ${line} | awk -F":" '{print $2}'
++ awk -F: '{print $2}'
++ echo mx.example1.com:2225
+ mxg_port=2225
+ echo 'Connecting and Upgrading mx.example1.com'
Connecting and Upgrading mx.example1.com
+ ssh root@mx.example1.com -p 2225 'aptitude update && aptitude safe-upgrade -y && reboot && exit'
Hit http://mirror.aarnet.edu.au lenny Release.gpg
Ign http://mirror.aarnet.edu.au lenny/main Translation-en_AU
..... truncated for readability of post ....
Hit http://volatile.debian.org lenny/volatile/non-free Sources
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
Reading extended state information...
Initializing package states...
Reading task descriptions...
No packages will be installed, upgraded, or removed.
0 packages upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 0B of archives. After unpacking 0B will be used.
Reading package lists...
Building dependency tree...
Reading state information...
Reading extended state information...
Initializing package states...
Reading task descriptions...
+ read line
>

If I remove the SSH line it works:

> /usr/local/bin/updatemxg.sh
Connecting and Upgrading mx.example1.com
Connecting and Upgrading mail.example2.com
Connecting and Upgrading mail.example3.com
>

If the remote ssh exit is indeed causing the while loop to stop how would I prevent that happening

You really do not need to exit since it is going to reboot. Alternatively try to use shutdown with a delay (say 1 minute)

'aptitude update && aptitude safe-upgrade -y && shutdown -r +1

BTW, there is a simpler and efficient way to pass the colon separated files to read using IFS (internal field separator). Below code tells read to change the default IFS (which is white space) to colon.

while IFS=":" read mxg_host mxg_port
do
  echo $mxg_host
  echo $mxg_port
done < /etc/mxg/ssh-hosts

Thanks chihung, I tried your suggestion but it still fails, so the exit doesn't appear to be the problem. If I check the return value from the ssh command it is 0, so i'm stumped? Thanks for the IFS suggestion.

The script currently looks like this:

#!/bin/bash

mxg_hosts_file="/etc/mxg/ssh-hosts"

while IFS=":" read mxg_host mxg_port ; do
    echo "Connecting and Upgrading ${mxg_host}"
    ssh root@${mxg_host} -p ${mxg_port} 'aptitude update && aptitude safe-upgrade -y && shutdown -r now'
done < ${mxg_hosts_file}

Edit - figured it out.

You have to use ssh's -n argument.

 -n      Redirects stdin from /dev/null (actually, prevents reading from
             stdin).  This must be used when ssh is run in the background.  A
             common trick is to use this to run X11 programs on a remote
             machine.  For example, ssh -n shadows.cs.hut.fi emacs & will
             start an emacs on shadows.cs.hut.fi, and the X11 connection will
             be automatically forwarded over an encrypted channel.  The ssh
             program will be put in the background.  (This does not work if
             ssh needs to ask for a password or passphrase; see also the -f
             option.)

Please have a look at this: Shell Loop Interaction with SSH
A better solution is to use the for loop

for line in $(cat ${mxg_hosts_file}); do
    echo "Connecting and Upgrading ${line%%:*}"
    ssh root@${line%%:*} -p ${line##*:} "bash -s" < command_to_run
done 

command_to_run is a script that you intended to execute on the remote boxes

aptitude update 
aptitude safe-upgrade -y
shutdown -r now