3

I'm trying to write my first ever shell script. The code I have written must be executed whenever a certain database has been modified. The database resides on a Windows server to which I have a mount point. Here is the script I have written to date:

#!/bin/sh

DB1=/mnt/reckon/"Point of Sale Lite 2013 Administrator"/QBPOS.PDB

ls -la "$DB1"

if [ "$DB1" -nt "~/scripts/file1" ]; then
  echo "Database has updated since last run"
  echo "Do some stuff here"
  touch file1
else
  echo "Database has not been updated"
fi

Unfortunately, no matter what, the script ALWAYS equates to false. This is an ls of DB1 at the beginning of the script just for debugging so I can see if the DB1 declaration is successful.

This is an ls for my file1:

pi@mckinnonPi ~/scripts $ ls -l file1
-rw-r--r-- 1 pi pi 0 Jun 20 10:27 file1

This is an ls for the database:

pi@mckinnonPi ~/scripts $ ls -l /mnt/reckon/"Point of Sale Lite 2013     Administrator"/QBPOS.PDB
-rwxr-xr-x 1 root root 2048000 Jun 22 14:30 /mnt/reckon/Point of Sale Lite 2013     Administrator/QBPOS.PDB

As you can see the database file is certainly newer than file1, however if I now run the script this is what I get:

pi@mckinnonPi ~/scripts $ ./fileage 
-rwxr-xr-x 1 root root 2048000 Jun 22 14:36 /mnt/reckon/Point of Sale Lite 2013 Administrator/QBPOS.PDB
Database has not been updated
pi@mckinnonPi ~/scripts $ 

So clearly the declaration for DB1 is working, as the ls command in the script succeeds, but for some reason the file age test fails. I've been working on this for a few days now, and I've researched as much as I can but have hit a brick wall. Any help would be very much appreciated.

Thank you!

  • Update

I've re-written the script in order to simplify as much as possible. When using paths that do NOT contain a space everything works exactly as expected so when I run this script:

#!/bin/sh

# DB1=/mnt/qnap/Amarillo/Reckon/"Point of Sale Lite 2013 Administrator"/QBPOS.TXT
DB1=/tmp/test/file2
TF1=/home/pi/scripts/file1

ls -la "$DB1"
ls -la "$TF1"

if [ "$DB1" -nt "$TF1" ]; then
    echo "Database has been updated since last run"
    echo "Do some stuff here"
    touch /home/pi/scripts/file1
else
    echo "Database has NOT been updated"
fi

The conditional statement works exactly as I would expect. Unfortunately, when I change the test to use the path including spaces it fails again. This is so frustrating! I've also tried using a symbolic link but the same problem occurs.

OK, so I'm new to stack overflow, so I don't understand how this has been marked as duplicate and answered? As I have explained in my update above, removing all reference to the tilde makes NO DIFFERENCE, this problem has nothing to do with the tilde expansion, as you can see in the updated code above.

Please don't mark something as answered if you have not read and understood the question fully .

Kelly Norton
  • 487
  • 2
  • 4
  • 19
  • Are you running Ubuntu (or an Ubuntu derivative)? – Elliott Frisch Jun 22 '14 at 04:51
  • 3
    You are quoting the tilde. Don't. – n. m. could be an AI Jun 22 '14 at 04:52
  • Thanks for the response. I am running Raspbian on a Raspberry Pi. – Kelly Norton Jun 22 '14 at 06:57
  • Removed any reference to tilde just to be sure. Still get the same result. – Kelly Norton Jun 22 '14 at 10:15
  • I cannot reproduce your results. Can you rewrite the script such that it is self-contained (i.e creates all files it uses and places everything under /tmp)? – n. m. could be an AI Jun 22 '14 at 17:26
  • I can give it a try! Obviously I can't change the location of the database but I can certainly update the handling of file1. I'll edit it shortly and post up the results. – Kelly Norton Jun 22 '14 at 17:56
  • I have changed the code to reference only files on the local system, and even though my testing directory structure contains spaces IT WORKS! I simply don't understand this, it would appear the root cause is the fact the database file resides on a CIFS share but why would that cause a problem? – Kelly Norton Jun 22 '14 at 18:25
  • **SOLVED** It was so simple, and I still don't understand why, but changing the shell solved the problem. Instead of #!/bin/sh I changed it to #!/bin/bash and it is now working perfectly. – Kelly Norton Jun 22 '14 at 18:51

3 Answers3

2

While others have correctly noted that placing a ~ within quotes will prevent shell expansion, you are free to move it outside the quotes and expansion will then work fine. For example the following works fine:

#!/bin/sh

if [ -f ~/"fname w spaces.txt" ]; then
    printf "fname w spaces -- Found\n"
else
    printf "fname w spaces -- NOT Found\n"
fi

exit 0

In your case, changing the if conditional to the following and moving the ~ outside the quotes will allow expansion:

if [ "$DB1" -nt ~/"scripts/file1" ]; then
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Thanks for your reply. I've tried re-writing the entire script, this time removing quotes around the tilde entirely to simplify things as much as possible. Unfortunately the if statement still fails :( – Kelly Norton Jun 22 '14 at 10:01
  • @user3746802 show me the if statement your are using (and the updated code containing all relevant variable assignments), and show me a `readlink -f` to the fname\ w\ spaces.txt you are trying to test. For example `readlink -f fname\ w\ spaces.txt`. That will provide the complete path for the file so we can verify your setup. – David C. Rankin Jun 22 '14 at 17:44
  • Moving the tilde outside the quotes will allow it to expand, but it will also allow it to wordsplit, defeating the point of having the quotes around the rest of the string. At that point, it's probably better to use `"$HOME/file with spaces.txt"`. – kojiro Jun 22 '14 at 17:59
  • Hi David. Here is the output requested: pi@mckinnonPi ~/scripts $ readlink -f /mnt/qnap/Amarillo/Reckon/Point\ of\ Sale\ Lite\ 2013\ Administrator/QBPOS.TXT /mnt/qnap/Amarillo/Reckon/Point of Sale Lite 2013 Administrator/QBPOS.TXT pi@mckinnonPi ~/scripts $ – Kelly Norton Jun 22 '14 at 18:08
  • And I have added the updated code to the bottom of the original post so it looks neat, pasting it in these comment field is very ugly :) – Kelly Norton Jun 22 '14 at 18:10
  • Just a quick note, I've had to change the file I am using for testing as it's 4am here and I have no access to the production network from home. No matter however, I still experience the same problem! – Kelly Norton Jun 22 '14 at 18:12
  • **SOLVED** It was so simple, and I still don't understand why, but changing the shell solved the problem. Instead of #!/bin/sh I changed it to #!/bin/bash and it is now working perfectly. – Kelly Norton Jun 22 '14 at 18:52
0

Judging from the listing you provided, I think that the problem is that you either have multiple spaces or a TAB after "2013". If you use whitespace in a pathname, Linux is not going to use clever fuzzy matching to try and figure out what you / the user means. As far as Linux pathnames are concerned, one space is different to two ... etc.

A second problem (spotted by @n.m !) is that you are quoting the pathname starting with ~. That will suppress the expansion of the ~ to the user's home directory.


In addition, I would have written the first line as:

    DB1="/mnt/reckon/Point of Sale Lite 2013 Administrator/QBPOS.PDB"

It doesn't make any material difference, but it is (IMO) neater.

Also, I would try to avoid using or allowing pathnames with whitespace in Linux applications them because they tend to be troublesome. It is not uncommon for scripts to be written on the assumption that there are no whitespaces. It is easiest to "play it safe".

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I've just tried re-typing the entire script from scratch, avoiding any form of copy and paste. I still get the same error so I don't believe there are any erroneous spaces, tabs etc. I also agree on the second point making reading the code easier. I had tried every permutation available but no difference in outcome I'm afraid. – Kelly Norton Jun 22 '14 at 09:51
  • In that case, you must have made a mistake in copy-pasting the directory listing into the Question, because it has TWO spaces there. – Stephen C Jun 22 '14 at 14:24
  • Could you please show me exactly where there are 2 spaces? I have looked again and can not see any double spacing. If you are referring to the 'ls' output then perhaps it was a pasting mistake, but I can;t find any double spacing in the actual shell script that may be causing the issue Thank you. – Kelly Norton Jun 22 '14 at 17:21
  • Look for this line: `ls -l /mnt/reckon/"Point of Sale Lite 2013 Administrator"/QBPOS.PDB`. Open the Question in edit mode and count the characters. – Stephen C Jun 22 '14 at 22:03
0

Instead of #!/bin/sh I changed it to #!/bin/bash and it is now working perfectly. For some reason dash does not support the -nt test flag under certain conditions. It works just fine when all files are stored on the local filesystem, but refuses to work correctly accessing network shares.

Changing the shell to bash "#!/bin/bash" solved the problem and now the script works perfectly. Thank you to everyone that helped, I have learned a lot from this little exercise!

Kelly Norton
  • 487
  • 2
  • 4
  • 19