Shell script worked correctly until I added variable :(

Hi everyone,

I have been using a shell script for the last 6 months to copy a database from a POS system, then analyse the database and print the current sales total. This has worked flawlessly, the only issue was that I had hard coded the IP address of the POS and occasionally I would need to edit the script to reflect the change. I decided to set the IP address programatically, and after playing around to find an easy way to detect the address I added a small piece of code to the previously working script.

Unfortunately the change I made has had an unexpected result, and the script no longer works as it should. The script accepts a single command line argument to specify if the processing should occur on a local copy of the database, or if a new version should be copied from the POS prior to processing, and it appears that the changes I made have broken the IF statement I use to perform that decision, based on the passed parameter. Here is the script before the changes:

#!/bin/bash

 if [[ $1 = "full" ]]
then
        sudo umount /mnt/reckon
        sudo mount.cifs //192.168.0.36/reckon /mnt/reckon -o user=posquery,password=**********,ro
        cp /mnt/reckon/Point\ of\ Sale\ Lite\ 2013\ Administrator/QBPOS.PDB /home/pi/
        echo "Select DateTime, ItemName, AmountGrossIncTax from Transaction where FunctionCaption='Total'" | mdb-sql -p /home/pi/QBPOS.PDB | grep $(date +"%m/%d/%y")
        echo
        printf "Total: $"
        echo "Select DateTime, ItemName, AmountGrossIncTax from Transaction where FunctionCaption='Total'" | mdb-sql -p /home/pi/QBPOS.PDB | grep $(date +"%m/%d/%y") | awk '{print $3}' | awk '{x+=$0}END{print x}'

elif [[ $1 = "local" ]]
then
        printf "Total: $"
        echo "Select DateTime, ItemName, AmountGrossIncTax from Transaction where FunctionCaption='Total'" | mdb-sql -p /home/pi/QBPOS.PDB | grep $(date +"%m/%d/%y") | awk '{print $3}' | awk '{x+=$0}END{print x}'
else
        umount /mnt/reckon
        sudo mount.cifs //192.168.0.36/reckon /mnt/reckon -o user=posquery,password=**********,ro
        cp /mnt/reckon/Point\ of\ Sale\ Lite\ 2013\ Administrator/QBPOS.PDB /home/pi/
        printf "Total: $"
        echo "Select DateTime, ItemName, AmountGrossIncTax from Transaction where FunctionCaption='Total'" | mdb-sql -p /home/pi/QBPOS.PDB | grep $(date +"%m/%d/%y") | awk '{print $3}' | awk '{x+=$0}END{print x}'
fi

As I said, the above code works perfectly. Here is the script after I updated it to find the IP address problematically, changes highlighted in red:

#!/bin/bash

ipaddress="$(nmblookup frontofhouse-pos | awk 'FNR == 2 {print $1}')"

echo $ipaddress

echo $1

 if [[ $1 = "full" ]]
then
        sudo umount /mnt/reckon
        sudo mount.cifs //"$ipaddress"/reckon /mnt/reckon -o user=posquery,password=**********,ro
        cp /mnt/reckon/Point\ of\ Sale\ Lite\ 2013\ Administrator/QBPOS.PDB /home/pi/
        echo "Select DateTime, ItemName, AmountGrossIncTax from Transaction where FunctionCaption='Total'" | mdb-sql -p /home/pi/QBPOS.PDB | grep $(date +"%m/%d/%y")
        echo
        printf "Total: $"
        echo "Select DateTime, ItemName, AmountGrossIncTax from Transaction where FunctionCaption='Total'" | mdb-sql -p /home/pi/QBPOS.PDB | grep $(date +"%m/%d/%y") | awk '{print $3}' | awk '{x+=$0}END{print x}'

elif [[ $1 = "local" ]]
then
        printf "Total: $"
        echo "Select DateTime, ItemName, AmountGrossIncTax from Transaction where FunctionCaption='Total'" | mdb-sql -p /home/pi/QBPOS.PDB | grep $(date +"%m/%d/%y") | awk '{print $3}' | awk '{x+=$0}END{print x}'
else
        umount /mnt/reckon
        sudo mount.cifs //"$ipaddress"/reckon /mnt/reckon -o user=posquery,password=**********,ro
        cp /mnt/reckon/Point\ of\ Sale\ Lite\ 2013\ Administrator/QBPOS.PDB /home/pi/
        printf "Total: $"
        echo "Select DateTime, ItemName, AmountGrossIncTax from Transaction where FunctionCaption='Total'" | mdb-sql -p /home/pi/QBPOS.PDB | grep $(date +"%m/%d/%y") | awk '{print $3}' | awk '{x+=$0}END{print x}'
fi

Unfortunately, when I run the script now I receive the following error, which point directly to the IF and ELSEIF lines:

./ip: 7: ./ip: [[: not found
./ip: 17: ./ip: [[: not found

Clearly I have broken the IF statement block with the addition of the ipaddress= assignment, but I don't understand why, or how to fix it?

I added the echo statements at the beginning of the script for testing, and both the ipaddress variable and the passed command line parameter are still correct, so what have I done wrong?

Any help would be most appreciated!

Thank you.

This looks fishy to me. It seems like carriage returns have ended up in there. How did you edit this file?

I edited the script using nano. The text above I ran through notepad to remove passwords before posting it here so maybe notepad has messed up the text?

Actually thinking about it, I may have performed the real changes in notepad, then pasted them back in to the script using nano. Could that have killed it?

It's possible. Try this.

tr -d '\r' < original.sh > fixed.sh

Try using [ expr ] instead of [[ expr ]] .
Just had the same thing when running a script.

1 Like

I just gave that a try and no difference unfortunately.

did you try original.sh or fixed.sh ?

OK well that has made a huge difference, I can't test 100% until the POS is back online but it appears to have fixed most of the problem. Now when I run the script I do not see the error any more when I pass a parameter, so the following appear to work correctly:

./ip full
./ip local

However if I execute the script with no parameters I once again see the error:

./ip: 7: [: =: unexpected operator
./ip: 17: [: =: unexpected operator

So nearly there, and I can fully test in another hour when the POS comes back online.

---------- Post updated at 03:54 PM ---------- Previous update was at 03:53 PM ----------

fixed.sh

Was just going to edit, but since its a new page i'll do a new post.

What i've forgotten to add was this, use quotes when checking for empty string.

[ -z "$1" ] && ...

That way it will not fail if its empty.
The double [[ did stop that message from appearing, but now with single brackets, you need to quote.

hth

2 Likes

Well look at that, no more errors!

Thank you very much sea, I'll complete full testing once the POS is online and post up how I go.

Thank you everyone for your help, I really appreciate it.

The only explanation I would have that it is not bash that is being run somehow. The error messsages are not typical of bash. They look more like those of ash or dash to me, which does not understand double square brackets. Probably on that particular system /bin/sh points to ash or dash and that is what gets called somehow, or maybe someone made a symlink from /bin/bash to ash or dash. However, I do not understand how the first script could run OK then..

/bin/sh points to dash.

This is a default raspbian system, running on a raspbery pi. I haven't changed anything really, and /bin/bash is not a symlink so it "should" be running correctly I guess? Is there any way I can check which shell is being called?

Well then for sure dash is being called, the error messages are not bash . How do you call the script?

Direct from the command line eg. "sudo ./ip full"

Are #! the first two characters of the file? No space before it or a line before it? What does ls -l /bin/*sh give ?
What happens when you call it like sudo /bin/bash ./ip full

Hmmmmm, there is a space before the #!

-rwxr-xr-x 1 root root 813992 Sep 26 06:55 /bin/bash
-rwxr-xr-x 1 root root 88340 Mar 30 2012 /bin/dash
lrwxrwxrwx 1 root root 4 Sep 26 06:55 /bin/rbash -> bash
lrwxrwxrwx 1 root root 4 Mar 30 2012 /bin/sh -> dash

./ip: line 7: [: =: unary operator expected
./ip: line 17: [: =: unary operator expected

Different error. Is that space before the #! an issue? I love learning new stuff!

That is the exact problem! The #! needs to be the exact first two characters. Otherwise it is a comment and it gets ignored...
So therefore the default shell got called instead which is /bin/sh which points to dash .

1 Like

As I said, it's great to learn new things :slight_smile:

Thank you, the script now runs without errors, and even better, I understand why!

1 Like

If using = operator in test command, then you need value before it and after it.
If $1 is empty then you have nothing. => test cmd syntax error.
But "$1" is always something, sometimes string which length is 0.

# ex. make next change and no problem in syntax
#  if [[ $1 = "full" ]]
# =>
if [ "$1" = "full" ]

Not only that, but if $1 is left unquoted in the test command [ ... ] , it will be subjected to field splitting and pathname expansion by the shell.
When using the double bracket bash/ksh/zsh shell grammar [[ ... ]] , this will not be done...