Need to create a simple script using MD5, SSH...

My psychic powers tell me you're missing a... a... 'fi'! Somewhere in line... line... um...

I'm sorry, I can't continue this psychic debugging session until you insert $3.99 into your CDROM.

...either that or post your code :stuck_out_tongue: We can't see it from here!

I used the suggestion from Chubler. Namely:

#!/usr/bin/sh 
 
while read fname; do 
    bname=$(basename $fname) 
    first=0 
    {
      hostname
      /usr/local/bin/hosts
    } | while read box; do 
        t=$(ssh ${box} "/usr/local/bin/md5 /opt/dba/scp/$bname" | awk '{print $4}') 
        if [ $first -eq 0 ]; then 
            hash=$t
            first=1 
        else 
            [ "${hash}" == "${t}" ] || echo Files are not Identical!!!
        fi 
 
    done 
done < /home/izivanov/iz3

You said you incorporated it, not copied it letter-for-letter...

Could you put echo statements inside the loops to see where it's hanging?

#!/usr/bin/sh 
 
while read fname; do 
    bname=$(basename $fname) 
    echo "trying "${fname} (${bname})" >&2
    first=0 
    {
      echo "running hostname" >&2
      hostname
      echo "finished running hostname, now running /usr/local/bin/hosts" >&2
      /usr/local/bin/hosts
    } | while read box; do 
        echo "ssh-ing to box ${box}" >&2
        t=$(ssh ${box} "/usr/local/bin/md5 /opt/dba/scp/$bname" | awk '{print $4}') 
        if [ $first -eq 0 ]; then 
            hash=$t
            first=1 
        else 
            [ "${hash}" = "${t}" ] || echo "Files are not Identical!!!"
        fi 
 
    done 
done < /home/izivanov/iz3

Also fixed some might-have-been-syntax errors, highlighted in red. Not all shells know what == means, but = should go. And you shouldn't have loose !'s hanging around unquoted, in some shells ! is a history command.

[ "${hash}" = "${t}" ] || echo "Files are not Identical!!!"

Shouldn't it be "!=" where the "=" is? I want to have the echo statement say that when the files are not the same, right?

Thank you!

---------- Post updated at 12:21 PM ---------- Previous update was at 12:02 PM ----------

It says:

Syntax error on line 5 : '(' is not expected!

this || that means "run this, and if it fails, run that". So if it's not equal, it runs echo ...
The && syntax is the opposite: run this, if it succeeds, run that.

It's very handy for chaining a number of dependent commands in a row without needing n+1 levels of nested if. a && b && c && d && e will stop at b if b fails.

My bad, I put an extra quotation mark in that. Substitute this line:

echo "trying ${fname} (${bname})" >&2

Wow okay here we go finally:

(root):/home/izivanov# sh dirsync3.sh
trying /opt/dba/scp/xxxxxxxx (xxxxxxxxxxxc)
running hostname
ssh-ing to box xxxxxxx
finished running hostname, now running /usr/local/bin/hosts
trying /opt/dba/scp/xxxxxxxxx (xxxxxxxxxx)
running hostname
ssh-ing to box xxxxxxxx
finished running hostname, now running /usr/local/bin/hosts
trying /opt/dba/scp/xxxxxxxxxxx (xxxxxxx)
running hostname
ssh-ing to box xxxxxx
finished running hostname, now running /usr/local/bin/hosts
trying /opt/dba/scp/xxxxxxxxxx (xxxxxxxxxxxx)
running hostname
ssh-ing to box xxxxxx
finished running hostname, now running /usr/local/bin/hosts
trying /etc/sudoers (sudoers)
running hostname
ssh-ing to box xxxxxxx
finished running hostname, now running /usr/local/bin/hosts
trying /opt/dba/binxxxxxxxxxx (xxxxxxxxxxxx)
running hostname
ssh-ing to box xxxxxxx
finished running hostname, now running /usr/local/bin/hosts

At least that's output! Confused on the output. It doesn't give me much useful info about which box these files are not identical to the original box...

---------- Post updated at 02:31 PM ---------- Previous update was at 02:25 PM ----------

Looks like its just running the hosts and hostname and not recognizing them as executables!

---------- Post updated at 02:33 PM ---------- Previous update was at 02:31 PM ----------

Somehow its supposed to run the MD5 on the file against the "hosts" file and also "hostname" which is the current box name from which I'm running this script!

You were running these files as executables before -- maybe accidentally, but that had me assuming they were scripts. Are they actually just text files?

Sorry here is the hosts file:

cat <<-EnD | egrep -vx "`/usr/bin/hostname`"
box 1
box 2
~
~
~
box n
EnD

And the hostname is just an executable that brings up the hostname of the server I am on currently! Host is also an executable file!

Well, if it's printing "ssh-ing to box rtidsva", it must be pulling that name from somewhere, so I think it really is executing those two programs and reading the names appropriately.

I assume this 'first' variable is to compare all following with the local host. Why not do that separately to avoid confusion and cut a big chunk of extra logic out?

#!/usr/bin/sh 
 
while read fname; do 
    bname=$(basename $fname) 
    echo "trying "${fname} (${bname})" >&2

    hash=$(/usr/local/bin/md5 /opt/dba/scp/$bname | awk '{print $4}')

    echo "local hash is ${hash}"

    /usr/local/bin/hosts | while read box ; do 
        echo "ssh-ing to box ${box}" >&2
        t=$(ssh ${box} "/usr/local/bin/md5 /opt/dba/scp/$bname" | awk '{print $4}') 
        echo "comparing ${hash} to ${t}" >&2
        [ "${hash}" = "${t}" ] || echo "Files are not Identical!!!"
    done 
done < /home/izivanov/iz3

When in doubt, print everything. :wink:

Okay we got something!

(root):/home/izivanov# sh dirsync5.sh
trying /opt/dba/scp/xxxxxxxxx (xxxxxxxxc)
local hash is xxxxxxxxxxxxxxxxxx
ssh-ing to box box2
comparing xxxxxxxxxxxxxxxxxxxxx to xxxxxxxxxxxxxxxxxxxxxxxx
~
~
~
~

Question why is it only ssh-ing into box 2?

Check what /usr/local/bin/hosts prints. That loop won't break until read fails for some reason. Try running /usr/local/bin/hosts by itself and see what it does.

You can't md5sum things like /etc/sudoers without root access. And automatic passwordless remote root access to every machine is scary, so maybe you don't want to check that one... That weird 'opened' must be part of an error message -- odd place for it to end up, I'd have expected them to go to stderr!

But we're getting there. It's definitely able to verify some files now.

1 Like

Btw I am running with root access. I didn't need to provide my login info to ssh with the script before to do this check either.

Its executable from anywhere with just "hosts" line. If I run it from Box 1 from which we make all our changes from, I get a list of all the boxes:

box 1(root):/home/izivanov# hosts
box 2
box 3
box4
~
~
~
box n
And if I run it from box 2, I'll get:

box 1
box3
box4
~
~
~
Box n

Do you understand?

So running the script from box 1, its getting only the first line of `hosts`, i.e. Box 2, and then not checking the file in question against that box either!

We also include `hostname' executable so that it would do this check on every box including the one I'm currently on, box 1! But it's not doing that!

I really don't understand why it's not looping through all hosts... When loops break down like that, simplify it until you get something that works as expected and build from there.

while read fname; do 
    bname=$(basename $fname) 
    echo "trying "${fname} (${bname})" >&2

    hash=$(/usr/local/bin/md5 /opt/dba/scp/$bname | awk '{print $4}')

    echo "local hash is ${hash}"

    # should just print the entire list of hosts repeatedly
    /usr/local/bin/hosts

done < /home/izivanov/iz3

Yup its exactly what happened!

It displayed the local hash, and then listed all of the servers. However I don't even need the see the hash. I just need to display on which server the hash doesn't correspond to the original file hash!

---------- Post updated at 12:35 PM ---------- Previous update was at 12:32 PM ----------

Sorry here is the output also:

(root):/home/izivanov# sh dirsync6.sh
trying /opt/dba/scp/xxxxxxxxxxx (xxxxxxx)
local hash is xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Box 2
box 3

etc

and then it repeats for all the files the same!

building from there:

while read fname; do 
    bname=$(basename $fname) 
    echo "trying "${fname} (${bname})" >&2

    hash=$(/usr/local/bin/md5 /opt/dba/scp/$bname | awk '{print $4}')

    echo "local hash is ${hash}"

    # should just print the md5's
    /usr/local/bin/hosts | while read box
    do
        # should print md5's repeatedly
        ssh ${box} "/usr/local/bin/md5" "/opt/dba/scp/$bname"
    done

done < /home/izivanov/iz3

---------- Post updated at 11:45 AM ---------- Previous update was at 11:41 AM ----------

...and if that works

while read fname; do 
    bname=$(basename $fname) 
    echo "trying "${fname} (${bname})" >&2

    hash=$(/usr/local/bin/md5 /opt/dba/scp/$bname | awk '{print $4}')

    echo "local hash is ${hash}"

    # should just print the md5's
    /usr/local/bin/hosts | while read box
    do
        # should print md5's repeatedly
        T=$(ssh ${box} "/usr/local/bin/md5" "/opt/dba/scp/$bname" | awk '{ print $4;}')
        [ "$T" = "$hash" ] || echo "${box} bname differs!"
    done

done < /home/izivanov/iz3

I just realized something. Not all the files you want to test are under /opt/dba/scp, are they? Not if you want to check /etc/sudoers!

Lol, I guess I am trained now to spot errors and remember them. You keep putting the " in
echo "trying "${fname} (${bname})" >&2
But now I notice it! Anyway, yeah here it is:

A couple of cannot open things on the bottom. Not really sure what that is!

---------- Post updated at 12:54 PM ---------- Previous update was at 12:50 PM ----------

Also what should I re-name the variable t with. My boss said that its not best practice to do that cause if anyone else looks at the script they won't know what the t stands for! I'm not sure what it stands for either! I know that it compares the hash-es of the files!

---------- Post updated at 12:55 PM ---------- Previous update was at 12:54 PM ----------

right, I was about to ask you about what to do if the files are different. My sync report got changed!

It's because not all your files are under /opt/dba/scp/. Check your list file and tell me, which ones should be converted from (whatever)/filename into /opt/dba/scp/filename, and which ones should be left as-is?

Or can they all be left as-is? In that case:

while read fname; do 
    #bname=$(basename $fname) 
    echo "trying ${fname}" >&2

    hash=$(/usr/local/bin/md5 "$bname" | awk '{print $4}')

    echo "local hash is ${hash}" >&2

    # should just print the md5's
    /usr/local/bin/hosts | while read box
    do
        T=$(ssh ${box} "/usr/local/bin/md5" "$fname" | awk '{ print $4;}')
        [ "$T" = "$hash" ] || echo "${box} $fname differs!"
    done

done < /home/izivanov/iz3

As for the syntax errors, ordinarily i'd try shell code I post on my own system before offering it to you but that's impossible for this script...

1 Like

No I'm just kidding. I'm incredibly thankful and learning a ton just from these little things you're showing me! THank you so much!

Here is the output of my directory sync report. Thats the original notification about what needs to be updated! Maybe that will help you!

So thats my original file I'm going off of!

Here is the ouput of the last change you suggested!

And sorry I had to remove the company server names. It might be confusing but I can't post that out here!

I'd be more interested in the contents of /home/izivanov/iz3 actually...

I spotted an error in my script. I left a bname in when inappropriate.

And one really should check the return value of md5 here. It bizzarely spews its errors to stdout, so whenever something goes wrong, the loop checks garbage vs garbage and decides everything's OK.

# If you don't have mktemp, TMP=/tmp/$$ will do.  mktemp is more secure.
TMP=`mktemp`
while read fname; do 
    #bname=$(basename $fname) 
    echo "trying ${fname}" >&2

    if ! /usr/local/bin/md5 "$fname" > "$TMP"
    then
        echo "md5 on ${bname} failed: "
        # print the error
        cat "$TMP"
        continue
    fi

    hash=$(awk '{print $4}' "$TMP")

    echo "local hash is ${hash}" >&2

    # should just print the md5's
    /usr/local/bin/hosts | while read box
    do
        T=$(ssh ${box} "/usr/local/bin/md5" "$fname" | awk '{ print $4;}')
        [ "$T" = "$hash" ] || echo "${box} $fname differs!"
    done

done < /home/izivanov/iz3

# clean up temp file
rm -f "$TMP"
1 Like

Here is the iz3 file!

And here is the output of me just ssh-ing and checking a hash on a file across box 2

---------- Post updated at 01:24 PM ---------- Previous update was at 01:20 PM ----------

And the last code suggestion you had! I think it gives the same output as before!