Unoffical empeg BBS

Quick Links: Empeg FAQ | RioCar.Org | Hijack | BigDisk Builder | jEmplode | emphatic
Repairs: Repairs

Topic Options
#371879 - 23/04/2019 05:10 Yet more Bash syntax help
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31563
Loc: Seattle, WA
Hey friends. I've been bashing my head against this one for a while, including doing a lot of googling and searching of StackOverflow. I'm hoping one of you kind folks can help with some expertise.

I have an "If" statement containing a "Find" statement within it, which works perfectly as long as the file being "found" doesn't reside a folder that contains spaces in the path name. As soon as spaces get in the mix, then it gives me an error: "Unary Operator Expected".

Here is an example script. There are two versions of the testFile variable. Depending on which one I uncomment, the script either works as expected, or it throws "Unary Operator Expected". (Note: A copy of the file exists in both places for the purposes of this test, both in the unspaced location and the spaced location.)

I've been trying various quoting options for the variable and none are working to improve the script. I've read through this but I must be missing something. Also, this may be a factor: I'm doing this at the Mac OS X shell, which has Bash version 3 instead of version 4.

Any ideas of what the correct syntax of that "find" statement should be?

Code:
#!/bin/bash

# This works as expected:
testFile="/Users/tonyfabris/Documents/test-file"

# This produces the error "Unary Operator Expected"
# when it hits the "find" command because of the
# space in the path name:
testFile="/Users/tonyfabris/Documents/Test Folder/test-file"

# Ensure the file is present. Works with both versions of the files.
if [ ! -f "$testFile" ]
then
  echo "Test file not found. Exiting."
  exit 1
fi
echo "Test file is present. Continuing program."

# Test the age of the file and only perform an operation
# if the file is more than 18 hours old.
if [ $( find "$testFile" -mmin +1080 ) ]
then
  echo "File is more than 18 hours old. Continuing with program."
else
  echo "No action will be performed based on the file age."
  exit 1
fi
echo "Performing action on the file."
_________________________
Tony Fabris

Top
#371880 - 23/04/2019 05:13 Re: Yet more Bash syntax help [Re: tfabris]
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31563
Loc: Seattle, WA
I just realized I punned unintentionally, but now I know why they call it "bash".
_________________________
Tony Fabris

Top
#371881 - 23/04/2019 07:58 Re: Yet more Bash syntax help [Re: tfabris]
Shonky
pooh-bah

Registered: 12/01/2002
Posts: 2009
Loc: Brisbane, Australia
The problem is that when your file is older than 18 hours your find command returns the filename not a true/false.

So you end up with

Code:
if [ /Users/tonyfabris/Documents/Test Folder/test-file ]


which has two "parameters" hence the error. When there's no space bash seems to return true for just a single parameter

When find doesn't match the file it returns "null" i.e.

Code:
if [ ]; then


Quick fix (I'm no bash expert). Something like:

Code:
#!/bin/bash

# This works as expected:
testFile="/build/christian/tmp/nospace-file"

# This produces the error "Unary Operator Expected"
# when it hits the "find" command because of the
# space in the path name:
testFile="/build/christian/tmp/space file"

# Ensure the file is present. Works with both versions of the files.
if [ ! -f "$testFile" ]
then
  echo "Test file not found. Exiting."
  exit 1
fi
echo "Test file is present. Continuing program."

# Test the age of the file and only perform an operation
# if the file is more than 18 hours old.
if [ "$( find "$testFile" -mmin +1080 )" != "" ]
then
  echo "File is more than 18 hours old. Continuing with program."
else
  echo "No action will be performed based on the file age."
  exit 1
fi
echo "Performing action on the file."
_________________________
Christian
#40104192 120Gb (no longer in my E36 M3, won't fit the E46 M3)

Top
#371882 - 23/04/2019 14:00 Re: Yet more Bash syntax help [Re: tfabris]
mlord
carpal tunnel

Registered: 29/08/2000
Posts: 14472
Loc: Canada
Why are you even using the "find" command in there? "find" is for locating files when you are uncertain of the exact path. But in the example here, at least, you do know the exact path. So what are you trying to have it do?

Checking for existence of a known pathname is easy:

if [ -e "$testfile" ]; then echo "it lives!" ; else echo "not there" ; fi

Also, the syntax used there for "find" doesn't make full sense to me. The "find" command takes a directory as a parameter, and searches within it for "files" which match any other parameters you supply based on name, date, size, etc.. But it doesn't look as it is being used correctly here

Puzzled! smile

Top
#371883 - 23/04/2019 15:55 Re: Yet more Bash syntax help [Re: tfabris]
canuckInOR
carpal tunnel

Registered: 13/02/2002
Posts: 3212
Loc: Portland, OR
He's using it as a sort of filter -- if the file is less than 18hrs old, the find command filters out the filename.

Top
#371884 - 23/04/2019 16:04 Re: Yet more Bash syntax help [Re: tfabris]
canuckInOR
carpal tunnel

Registered: 13/02/2002
Posts: 3212
Loc: Portland, OR
Perhaps a more canonical approach would be using date and stat:

Code:
cutoff=$((`date +%s`-64800))
age=`stat -c %Y "$testfile"`
# or, if your date command supports it:
# age=`date -r "$testfile" +%s`
if [ $age -gt $cutoff ]
then
    echo "File is too new."
    exit 1
fi
echo "File is over 18 hours old."


Top
#371885 - 23/04/2019 17:48 Re: Yet more Bash syntax help [Re: Shonky]
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31563
Loc: Seattle, WA
Shonky,

Thank you so much for that brilliant answer.

The reason that I was bashing my head against it was because I was convinced that the problem was with the syntax or the string-quoting of the variable being passed into the find command. I hadn't considered the possibility of the results coming back out of the command to be the root cause. Very cool, thank you.

Mark,

You're correct that it looks weird to use "find" to test the age of a file. After googling for the simplest and most reliable way to do that task, everyone on the internet seemed to agree that using the "-mmin" parameter of the find command was the best way. Looking at the built-in parameters to "find", it seems that indeed it's designed to do this very thing, and it does it quite well. The only issue with that method is that a true/false test must be done the way Shonky shows it, not the way I saw it in the first example I found on StackOverflow. Clearly the StackOverflow answer-er didn't test their example code with spaces in the path name.

Canuck,

Thank you so much for the alternative method of testing the file age. That is certainly a more direct way to do the test. I had preferred the simplicity of using the "find" command as a one-liner because the syntax was cleaner.
_________________________
Tony Fabris

Top
#371886 - 24/04/2019 11:05 Re: Yet more Bash syntax help [Re: tfabris]
Roger
carpal tunnel

Registered: 18/01/2000
Posts: 5680
Loc: London, UK
Originally Posted By: tfabris
spaces in the path name


People with a long history of using Unices don't use spaces in file names, because they break so many tools.
_________________________
-- roger

Top
#371887 - 24/04/2019 14:01 Re: Yet more Bash syntax help [Re: Shonky]
mlord
carpal tunnel

Registered: 29/08/2000
Posts: 14472
Loc: Canada
Originally Posted By: Shonky

Code:
# Ensure the file is present. Works with both versions of the files.
if [ ! -f "$testFile" ]
then
  echo "Test file not found. Exiting."
  exit 1
fi
echo "Test file is present. Continuing program."


Note that the test above does not seem to be necessary given the code changes suggested further on, and in fact also serves to introduce a race condition into the script: the file could be removed or created elsewhere between the two tests. In this case, the race doesn't matter (really!), but it also demonstrates that the pre-test for existence above isn't as useful as one might think.

It's really a shame that "find" doesn't return a non-zero exit status for cases where nothing is found. Doing so could simplify scripts like this one, but would also break many others.

Cheers

Top
#371888 - 24/04/2019 22:03 Re: Yet more Bash syntax help [Re: mlord]
tfabris
carpal tunnel

Registered: 20/12/1999
Posts: 31563
Loc: Seattle, WA
Quote:
People with a long history of using Unices don't use spaces in file names, because they break so many tools.


It took me a long time to get comfortable with spaces in file names on Windows, for similar reasons. And there too, I still sometimes find spaces break certain tools, or require the tool to be edited.


Quote:
Note that the test above does not seem to be necessary given the code changes suggested further on, and in fact also serves to introduce a race condition into the script


Good point. The actual code where I'm using this is structured differently, and so the race wouldn't exist. I put it into the example script, just to prove to myself that I wasn't crazy; that the file exists, and the quoting works for that file name in an "if" statement.
_________________________
Tony Fabris

Top
#371889 - 27/04/2019 01:14 Re: Yet more Bash syntax help [Re: tfabris]
jmwking
old hand

Registered: 27/02/2003
Posts: 768
Loc: Washington, DC metro
Yeah. No spaces here. Just underscores when appropriate/unavoidable.

-jk

Top