Expect in Bash - and then compare md5sum

I'm running on a staging server. I will need to use expect and I think ssh or scp to the other boxes.

I need to see something like this....

Enter:Host 1
Enter:Host 2

Enter full directory path to compare: example /apps/acd/jboss-customer1/

Enter User Id: 
Enter Password:

( Assumes they are the same for both boxes )

Then I need to basically create two files on the servers and scp them back to the main box say in /tmp and do a

 find $host1 -type f -name "*" | xargs -n 1 md5sum | sort -n >/usr/local/scripts/apps-ard-jboss-jpannprod-pd1.txt   

I need to do that on both boxes and then get them back to the main server to do the compare?

It's a bit jumbled in my mind sorry if I'm not being clear.

#!/bin/bash
clear
echo "================================== "
echo "Enter your Host 1 Name to compare"
echo "================================== "
echo -n "Host1 Name:"
read host1
clear
echo "================================== "
echo "Enter your Host 2 Name to compare"
echo "================================== "
echo -n "Host2 Name:"
read host2
clear
echo "================================== "
echo "Enter your Usr/Pw Authentication"
echo "================================== "
echo -n "UserName:"
read user
echo -n "Password:"
read password
/usr/bin/expect   <<EOF
set force_conservative 0
set timeout 4
spawn ssh $user@$name
expect "password:"
send  "$password\r"
expect "$"
send  "echo find $host1 -type f -name "*" | xargs -n 1 md5sum >/usr/local/scripts/apps-ard-jboss-jpannprod-pd.txt\r"

send "exit\r"

I am not sure that I understand the difference between this thread and your earlier thread: Compare md5sum two servers' setup. But, whether or not they are the same topic, I don't understand why you are trying to rewrite code to perform what rsync already does??? What makes you think that rsync only compares file sizes to determine if a file has changed?

Amen to that!

In addition: whenever you start to use expect this is the confession that something went horribly wrong in your setup.

If you plan your authorisation correctly you should never have to rely on expect (which is just a way of having passwords written in cleartext into scripts typed automatically into forms) but use (preexchanged) keys or something similar. Instead of fiddling around with expect-scripts you should simply test for a possible ssh-connection and raise an error if that doesn't work (because keys are not exchanged, are invalid or some other reason).

Here is how i do that. It first tests for IP-connectivity and then - if that is possible - for ssh-connectivity:

# ------------------------------------------------------------------------------
# f_CheckConnectivity                          checking connectivity for a host
# ------------------------------------------------------------------------------
# Author.....: Wolf Machowitsch
# last update: 2016 01 25    by: Wolf Machowitsch
# ------------------------------------------------------------------------------
# Revision Log:
# - 0.99   2007 01 18   Original Creation
#                       -
#
# - 1.00   2015 04 28   Production Version
#                       removed unecessary subshells
#
# - 1.01   2016 01 25   bugfix
#                       - changed ssh-call to cover for new hosts:
#                         added "-o 'CheckHostIP=no'"
#                         added "-o 'StrictHostKeyChecking=no'"
#
# ------------------------------------------------------------------------------
# Usage:
#     f_CheckConnectivity  char Hostname [ char user ]
#     checks the connectivity for the host given in $1 optionally using a
#     username given in $2. If no user name is given the current user is
#     assumed.
#
#     Example:  f_CheckConnectivity $host    # checks if $host can be worked on
#                                            # using the current user (usually
#                                            # this will be root)
#
# Prerequisites:
# -   to use this function, the FPATH variable must be set
#
# ------------------------------------------------------------------------------
# Documentation:
#     f_CheckConnectivity() checks in a successive manner. First an (IP)-ping
#     is issued. If this is successful a connection test is done by issuing
#     a command via ssh. f_CheckConnectivity() does NOT try to correct any
#     errors, merely stating them.
#
#     Parameters: char Host
#
#     returns:    0: connectivity test passed
#                 1: no ssh connection
#                 2: no IP connection
#                 3: parameter/other/internal error
#
# ------------------------------------------------------------------------------
# known bugs:
#
#     none
# ------------------------------------------------------------------------------
# .....................(C) 2007 Wolf Machowitsch ...............................
# ------------------------------------------------------------------------------

f_CheckConnectivity ()
{

$chFullDebug
                                                 # internal variables
typeset -i iRetVal=0                             # return value (see docu)
typeset    chHost="$1"                           # hostname
typeset    chUser="$2"                           # optional username

if [ -z "$1" ] ; then                            # check for prereqs
     iRetVal=3
elif [ "$chUser" == "" ] ; then
     chUser="$(who am i | cut -d' ' -f1)"
fi

if [ $iRetVal -eq 0 ] ; then
     if ! ping -c1 $chHost 1>/dev/null 2>&1 ; then
          iRetVal=2
     fi
fi
if [ $iRetVal -eq 0 ] ; then
     if ! ssh -nq                  \
              -o 'BatchMode=yes'   \
              -o 'CheckHostIP=no'  \
              -o 'StrictHostKeyChecking=no' \
                 ${chUser}@${chHost} date 1>/dev/null 2>&1; then
          iRetVal=1
     fi
fi

return $iRetVal

}
# --- EOF f_CheckConnectivity

Notice that you will have to adjust this if you deal with hosts in DMZs or behind firewalls, because they often block attempts to ping the host.

I hope this helps.

bakunin

1 Like

Hi.

I'll take the blame for this.

I had hoped that my quote from the rsync man page would encourage the OP to look farther into rsync . A more complete explanation of the workings of rsync can be found at rsync - Wikipedia, the free encyclopedia

If that is too difficult or does not meet the OP's requirements, then the MD5, sort, and compare steps seem reasonable to me.

Best wishes ... cheers, drl

I don't need to check connectivity but if config files are the same in certain directories. I am also not trying to sync them exactly the config files will have different IP addresses in them and different database names, this is why I can't just use rsync but was trying to hash something out that would tell me if they are different and list out the differences through making a couple of files and then doing a compare. Perhaps rsync will do this but I didn't think so.

So the script that you are hoping to create just gives you a list of files that need to be investigated further; it doesn't sync files. Isn't that exactly what:

rsync -n ... list_of_config_files_in_certain_directories ...

does?

The first time through it is likely to give you lots of false positives due to timestamp differences. But if you use rsync to synchronize those false positives (to sync the timestamps) and files that really need to be synced, subsequent runs should give you a greatly reduced list of files on which you actually need to perform your detailed md5sum checks.

And, obviously, if there are intentional IP and database name differences in some of your config files, md5sum isn't going to help you determine if there are also other differences in those files that shouldn't be present or that should cause a more complicated partial sync.

Don Cragun is right, rsync would be the solution of first choice.

But still, if this is ruled out somehow for some reason we have yet to find out:

If you do not need to check for connectivity then all the better. But in your threads title and the first post you mentioned you have to use "expect" and this can conceivably only be to transmit passwords. If you can guarantee somehow your ssh-keys can always be readily exchanged (though i'd still check that before i'd base my procedures on that) you can simply use ssh to remote-execute any command(s) you want and that would probably be a cleaner solution than using expect to initiate a pseudo-interactive ssh-session.

If you need to remotely execute arbitrary commands then you might want to do it this way (sketch):

while read HOST USER ; do
     if ! ssh -nqo 'BatchMode=yes' "$USER"@"$HOST" some_command
          echo "Error: some_command returned $?"
     fi
done <<_EOF_
host1 user1
host2 user2
....
_EOF_

Again, I'd check if indeed the keys are exchanged by including the function i showed you and call it somewhere inside the loop as part of my errror checking, but that is up to you. You should be able to build your custom routine around the shown mechanism pretty easily.

I hope this helps.

bakunin