3

in C-shell I need to check if a file exists or if it is older than another file (or in this example older than 5 seconds from the beginning of unix time). if the file does not exist or is old, some stuff should be executed.

In my example "bla.txt" does not exist, so the first condition is true

if ( ! -f bla.txt || `stat -c "%Y" bla.txt` > 5 ) echo 1
stat: cannot stat `bla.txt': No such file or directory
1

Problem is, if I combine these conditions in an if statement, the second one (age of file) is executed although the first one is already true and gives an error because the file is not there.

in bash, everything works as it should

if [ ! -f bla.txt ] || [ `stat -c "%Y" bla.txt` > 5 ]; then echo 1; fi
1

any ideas on how to achieve this behaviour in csh WITHOUT an else if? I don't want to have the commands to execute twice in my code.

thanks!

Radiodef
  • 37,180
  • 14
  • 90
  • 125
j-hap
  • 150
  • 1
  • 2
  • 9
  • I just realized how wrong the second condition in the if statement for the bash command is, but it's not executed so it does not matter ^^ – j-hap Jan 06 '16 at 08:56

2 Answers2

3

CSH has a parser which, to be honest, doesn't deserve the name.

The issue in this particular instance is that it doesn't evaluate the left side of the || construct first before starting stat (as you've seen). As you're depending on the standard output of stat you can't redirect output via >& /dev/null either, and redirection of just stderr is a bit of a nuisance (see Redirecting stderr in csh).

If you want clean csh code that is still understandable but do not want to code the actual code call twice, I think the cleanest solution is to use an intermediate variable. Something like this:

#!/bin/csh
set f=$1
set do=0
if ( ! -f $f ) then
  set do=1
else
  if ( `stat -c "%Y" $f >& /dev/null ` < 5 ) set do=1
endif

if ( $do ) echo "File $f does not exist or is older than 5s after epoch"

(Note that your original code also had the age test reversed from your prose.)

Community
  • 1
  • 1
fork2execve
  • 1,561
  • 11
  • 16
0

You can move the -f test inside the shell command from which you are redirecting the output of stat. Here is a script to illustrate:

#!/bin/csh                                                                 
set verbose
set XX=/tmp/foo
set YY=2
rm -f $XX
foreach ZZ ( 0 1 )
    if ( ` stat -c "%Y" $XX` > $YY ) echo 1
    if ( ` test -f $XX && stat -c "%Y" $XX` > $YY ) echo 1
    if ( $ZZ == 0 ) touch $XX
    stat -c "%Y" $XX
    sleep $YY
end
Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • This does not execute the desired command (the second echo 1 in your code) when the file does not exist. – fork2execve Jan 06 '16 at 20:16
  • Actually, OP's *question* as such was how to eliminate the error message. If I had rewritten OP's script, I might have done it differently (and still in one line, as OP requested). – Thomas Dickey Jan 06 '16 at 20:30