[comp.unix.questions] how to compare file modification time in bourne shell script

aab@silma.com (Andy Burgess) (07/24/90)

I need to compare the modification times of two files in a bourne shell
script. I would like to do this without writing C code.
Machine is Sparcstation 1 running SunOS 4.03c

Thus I need a function:

newer file1 file2

that returns 0 if file1 is newer than file2 else returns 1

Can it be done?

Andy Burgess
uunet!silma!aab
408 725 8908

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (07/25/90)

In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:
: 
: I need to compare the modification times of two files in a bourne shell
: script. I would like to do this without writing C code.
: Machine is Sparcstation 1 running SunOS 4.03c
: 
: Thus I need a function:
: 
: newer file1 file2
: 
: that returns 0 if file1 is newer than file2 else returns 1
: 
: Can it be done?

Several ways.

[ X`find file2 -newer file1 -print` = X ]

perl -e 'exit ((stat("file1"))[9] < (stat("file2"))[9])'

ls -lt file1 file2 | tail -1 | grep file2 >/dev/null

All of these should work on a Sun.  Some machines may not have a -newer
option to find or a grep that returns a reasonable status.  Some really
primitive machines don't have Perl.  :-)

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

bjornmu@idt.unit.no (Bj|rn Munch) (07/25/90)

In article <1990Jul23.233044.2729@silma.com>, aab@silma.com (Andy
Burgess) writes:
|> 
|> I need to compare the modification times of two files in a bourne shell
|> script. I would like to do this without writing C code.
|> Machine is Sparcstation 1 running SunOS 4.03c
|> 
|> Thus I need a function:
|> 
|> newer file1 file2
|> 
|> that returns 0 if file1 is newer than file2 else returns 1
|> 

I needed the same thing once, and did it this way:

  test `ls -lt file1 file2 | head -1 | grep file1`

This will not work if the name file1 is a substring of file2...

It really ought to be simpler; after all, ls *has* the information you
want, the rest is just needed to translate it.

___________________________________________________________________________
Bj|rn Munch                       | Div. of Comp. Science & Telematics,
bjornmu@idt.unit.no               | Norwegian Institute of Technology (NTH),
"The Man With a Pipe in His Name" | Trondheim, Norway

leo@ehviea.ine.philips.nl (Leo de Wit) (07/25/90)

In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:
|
|I need to compare the modification times of two files in a bourne shell
|script. I would like to do this without writing C code.
|Machine is Sparcstation 1 running SunOS 4.03c
|
|Thus I need a function:
|
|newer file1 file2
|
|that returns 0 if file1 is newer than file2 else returns 1
|
|Can it be done?

This is simple if you let make decide:

case `echo "file1 : file2; :"| make -f -` in
:) echo file1 is older than file2;;
*) echo file1 is newer than file2;;
esac

(this does not exactly return 0 or 1, but you get the intent).

On the other hand, many scripts I encounter that have to decide whether
file1 is newer than file2 are of type makefile; you might want to check
whether your problem fits this category.

    Leo.

celvin@EE.Surrey.Ac.UK (Chris Elvin) (07/25/90)

In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:
>
>I need to compare the modification times of two files in a bourne shell
>script. I would like to do this without writing C code.
>Machine is Sparcstation 1 running SunOS 4.03c
>
>Thus I need a function:
>
>newer file1 file2
>
>that returns 0 if file1 is newer than file2 else returns 1
>

How's about

foobar=`find file2 -newer file1 -print | wc -l`

Shell variable foobar will be 1 if file2 is newer than file1
or to answer the question as stated

foobar=`find file1 !-newer file2 -print | wc -l`



		Hope this helps

			C.
-- 
Chris Elvin
C.Elvin@EE.Surrey.Ac.UK                    "Beware of low flying butterflies!"
Dept of Elec. Eng, University of Surrey,
Guildford, Surrey, GU2 5XH. England. PHONE: +44 483 509104  FAX: +44 483 34139

mab@ulysses.att.com (Muhammad Basit) (07/25/90)

In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:
>
>I need to compare the modification times of two files in a bourne shell
>script. I would like to do this without writing C code.
>Machine is Sparcstation 1 running SunOS 4.03c
>Thus I need a function:
>newer file1 file2
>that returns 0 if file1 is newer than file2 else returns 1

Another way you might find useful is to use find. 
e.g.:
	find mbox -newer .profile -exec date \;

will execute the command date if 'mbox' is newer than '.profile'

I think you can use it for your work with little effort.

>Andy Burgess

Muhammad Basit
---------------
Muhammad Basit				A person's mind is like a parachute:	
Email:	mab@ulysses.ATT.COM		To work it first has to be open.
	Basit@Mars.NJIT.EDU				- I. Dont Remember

chet@cwns1.CWRU.EDU (Chet Ramey) (07/26/90)

In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:

>newer file1 file2
>that returns 0 if file1 is newer than file2 else returns 1

Here's something I picked up a while back...

/*
 * From Henry Spencer
 *
 * > There doesn't appear to be any decent way to compare the last modified
 * > times of files from the shell...
 *
 * Before everybody starts inventing their own names for this, it should be
 * noted that V8 already has a program for this, newer(1).  It takes two
 * filenames as arguments, and exits with status 0 if and only if either
 * (a) the first exists and the second does not, or (b) both exist and the
 * first's modification time is at least as recent as the second's.  Other-
 * wise it exits with non-zero status.  (The preceding two sentences are
 * essentially the whole of the manual page for it.)
 * 
 * Relatively few people have V8, but in the absence of any other precedent
 * for what this facility should like look, it seems reasonable to follow
 * V8's lead.
 * 
 * Here is an independent rewrite, done from the manual page and not the
 * code, by me, hereby placed in the public domain:
 */

/*
 * newer - is first file newer than second?
 *
 * newer file1 file2
 *
 * exit with 0 status if file1 exists and file2 does not, or if file1's last
 * modified time is at least as recent as file2's.
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

main(argc, argv)
int argc;
char *argv[];
{
	struct stat file1;
	struct stat file2;

	if (argc != 3) {
		fprintf(stderr, "Usage: %s file1 file2\n", argv[0]);
		exit(2);
	}

	if (stat(argv[1], &file1) < 0)
		exit(1);
	if (stat(argv[2], &file2) < 0)
		exit(0);
	if (file1.st_mtime >= file2.st_mtime)
		exit(0);
	exit(1);
}
-- 
Chet Ramey					``See Figure 1.''
Network Services Group
Case Western Reserve University	
chet@ins.CWRU.Edu		

mike@x.co.uk (Mike Moore) (07/26/90)

In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:
>
>I need to compare the modification times of two files in a bourne shell
>script. I would like to do this without writing C code.
>Machine is Sparcstation 1 running SunOS 4.03c
>
>Thus I need a function:
>
>newer file1 file2
>
>that returns 0 if file1 is newer than file2 else returns 1
>
>Can it be done?

Here is a way:

     newer() {
       file=$1
       set `ls -t $1 $2`   # func args are now changed
       [ $file = $1 ] && return 0 || return 1
     }

For those that don't know, the second line is an alternative form of:

     if [ $file = $1 ]
       then
         return 0
       else
         return 1
     fi

Of course, file1 and file2 have to exist, and have to be files.

If you don't want to use set, then:

     [ `ls -tC $1 $2 | sed 's/ .*$//'` = $1 ] && return 0 || return 1

And to do the whole thing properly:

     newer() {
       file=$1
       [ ! -f $1 -o ! -f $2 ] && return 2   # error exit
       set `ls -dt $1 $2`                   # func args are changed
       [ $file = $1 ] && return 0 || return 1
     }

Now file1 and file2 don't have to exist and don't have to be files.
Line #2 in this final version could be changed to two seperate lines:

     [ ! -f $1 ] && return 1  # since file2 is newer
     [ ! -f $2 ] && return 0  # since file1 is newer

if you want a different effect.

Using this method, then, on most machines, the only program actually read from
disk and executed is ls (some may actually execute the '[').

Happy Bourne Shell!

Mike
-- 
--------------------------------------------------------------------------
Usual disclaimer.....  etc                        | mike@x.co.uk
True Intelligence is not knowing all the answers, |
it's knowing the right questions.                 |

andre@targon.UUCP (andre) (07/26/90)

  In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:
  >I need to compare the modification times of two files in a bourne shell
  >script. I would like to do this without writing C code.
  >Machine is Sparcstation 1 running SunOS 4.03c

  >Thus I need a function:

  >newer file1 file2

  what about

  if [ -n "`find file2 -newer file1 -print`" ]
  then
    echo file2 is newer
  else
    echo file2 is not newer
  fi

-- 
The mail|    AAA         DDDD  It's not the kill, but the thrill of the chase.
demon...|   AA AAvv   vvDD  DD        Ketchup is a vegetable.
hits!.@&|  AAAAAAAvv vvDD  DD                    {nixbur|nixtor}!adalen.via
--more--| AAA   AAAvvvDDDDDD    Andre van Dalen, uunet!hp4nl!targon!andre

lanzo@wgate.UUCP (Mark Lanzo) (07/26/90)

Someone asks:
>
> I need to compare the modification times of two files in a bourne shell
> script. I would like to do this without writing C code.
> Machine is Sparcstation 1 running SunOS 4.03c

> Thus I need a function:
> 
> newer file1 file2
> 
> that returns 0 if file1 is newer than file2 else returns 1
> 

Try this:

#!/bin/sh

newer()
    {
    f1="$1"
    set -- `ls -ct -- "$f1" "$2"`
    test "$1" = "$f1"
    return $?			# This line isn't really necessary
    }

as written, this function presupposes that $1 and $2 refer to accessible
files (else the ls command will pop up with a "not found" type of error).



-- 
Mark Lanzo                      Wandel & Goltermann Technologies, Inc.
Home (919)481-2406              1030 Swabia Court
Play (919)941-5730              Research Triangle Park
uunet.uu.net!wgate.com!lanzo    North Carolina 27709-3585

chris@vision.UUCP (Chris Davies) (07/26/90)

In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:
>I need to compare the modification times of two files in a bourne shell
>script. I would like to do this without writing C code.

If you insist...  :-)

The function returns 0 if file1 is newer than file2.  Otherwise it returns 1.
Note that there is no check to ensure both files exist.
Syntax: newer file1 file2

newer() {
	F1=$1
	F2=$2

	echo "$F1\n$F2" > /tmp/newer$$
	if ls -t "$F1" "$F2" | cmp -s - /tmp/newer$$
	then
		RS=0
	else
		RS=1
	fi

	rm -f /tmp/newer$$
	return $RS
}

Have fun...
		Chris
-- 
VISIONWARE LTD         | UK: chris@vision.uucp     JANET: chris%vision.uucp@ukc
57 Cardigan Lane       | US: chris@vware.mn.org    OTHER: chris@vision.co.uk
LEEDS LS4 2LE          | BANGNET:  ...{backbone}!ukc!vision!chris
England                | VOICE:   +44 532 788858   FAX:   +44 532 304676
-------------- "VisionWare:   The home of DOS/UNIX/X integration" --------------

maart@cs.vu.nl (Maarten Litmaath) (07/27/90)

In article <Jul90.102745.21330@x.co.uk>,
	mike@x.co.uk (Mike Moore) writes:
)...
)     newer() {
)       file=$1
)       set `ls -t $1 $2`   # func args are now changed
)       [ $file = $1 ] && return 0 || return 1
)     }

Equivalently:

     newer() {
       file=$1
       set `ls -t $1 $2`   # func args are now changed
       [ $file = $1 ]
     }

Sic!
--
 "and with a sudden plop it lands on usenet.  what is it? omigosh, it must[...]
   be a new user! quick kill it before it multiplies!"      (Loren J. Miller)

chet@cwns1.CWRU.EDU (Chet Ramey) (07/27/90)

>newer file1 file2
>
>that returns 0 if file1 is newer than file2 else returns 1

If you didn't like the C program, then try this:

newer()
{
	if [ ! -f $1 ] ; then
		return 1
	fi

	if [ ! -f $2 ] ; then
		return 0
	fi

	if [ $1 -nt $2 ] ; then
		return 0
	else
		return 1
	fi
}

The `-nt' option to test exists in bash and ksh, at least.

Chet

-- 
Chet Ramey					``See Figure 1.''
Network Services Group
Case Western Reserve University	
chet@ins.CWRU.Edu		

jeff@onion.pdx.com (Jeff Beadles) (07/28/90)

In <8855@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
:In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:
:> 
:> I need to compare the modification times of two files in a bourne shell
:> script. I would like to do this without writing C code.
:> Machine is Sparcstation 1 running SunOS 4.03c
:> 
:> Thus I need a function:
:> 
:> newer file1 file2
:> 
:> that returns 0 if file1 is newer than file2 else returns 1
:> 
:> Can it be done?
:
:Several ways.
...
:ls -lt file1 file2 | tail -1 | grep file2 >/dev/null

This will only work some of the time.  What if file1 is "foobar" and file2 is
"bar" If you *had* to use this, I would recomend:

ls -lt file1 file2 | tail -1 | grep "^file2$" >/dev/null


UTek, the OS that I'm using now (UTek, a 4.2based OS.)  It has a couple of 
options to test:



TEST(1)                 COMMAND REFERENCE                 TEST(1)



NAME
     test - condition command

SYNOPSIS
     test expr [ expr ]

DESCRIPTION

...


     -C filename
               Time of the last status change to filename (see
               stat(2))

     -M filename
               Time of the last modification to filename (see
               stat(2))

     -A filename
               Time of the last access to filename (see stat(2))

...

Thus, you can use:
	if test -M file1 -le -M file2 ; then
		...
	else
		...
	fi


	-Jeff
-- 
Jeff Beadles		jeff@onion.pdx.com	jeff@quark.wv.tek.com

mayne@VSSERV.SCRI.FSU.EDU (William (Bill) Mayne) (07/30/90)

>:> Thus I need a function:
>:> 
>:> newer file1 file2
>:> 
Others have suggested the use of make to do this, or better yet just use
make to do whatever it is that depends upon file seniority. I think this
is the most efficient route in terms of using standard unix tools and
saving time. But the problem is not as simple as it seems, at least not
when using SunOS. (I don't know what other versions of unix share this
problem.) What if one of the files being compared is a symbolic link?
What modification date and time should be compared? I have been surprised
to learn the hard way that the date and time returned by ls and apparently
used by make is when the link was created, regardless of the last modification
to the actual file. Even if I later edit the file using the alias created
by a link rather than the base name it is the base name, not the link,
which gets a new modification date and time. I have some program constructions 
in which I have an awk program generate make files on the fly. Unless I
build in enough intelligence for them to track down the base file for each
reference I have quite a problem here. My first thought was to write a script
which uses to touch to bring the timestamps of links up to date with their
base files, but it turns out that touch also passes through to the base
file, leaving the link alone. The use of inodes and links described in,
for example, "The Unix Programming Environment" seemed so much more
straight forward and convenient. As a relative newcomer to unix I am
disappointed to find things rather different than what I had expected
after reading some of the gurus. The reasons why I can't easily just 
have all my make files refer to base files rather than links are too
complicated to go into here, but I am not just raising theoretical
arguments or flames. (I will supply more details if anyone asks.) Others
must have faced similar problems. I would be curious to know the reasons
why the system behaves in such a surprising way (IMHO), but even more
interested to know how others have worked with or around it in this
area.

Rereading this I see it is long. Just in case my main question gets
hidden in the fog, I will restate it: The timestamp of a symbolic link
is the time when the link was created, rather than the last modication
of the file ultimately referenced. Thus a make file which refers to 
a symbolic link is fooled. How, short of tracing down all symbolic links
when I generate a make file, can I work around this to use the actual
modification times of all files or links?  Other questions: If I really 
must trace down the links myself, is there an easy way to do it? 
Why was the system designed in a way that makes this use of make so 
difficult?

chris@mimsy.umd.edu (Chris Torek) (08/02/90)

In article <324@sun13.scri.fsu.edu> mayne@VSSERV.SCRI.FSU.EDU
(William (Bill) Mayne) writes:
>Others have suggested the use of make to [compare file modtimes]....
>Just in case my main question gets hidden in the fog, I will restate
>it: The timestamp of a symbolic link is the time when the link was
>created, rather than the last modication of the file ultimately
>referenced.

Right.

>Thus a make file which refers to a symbolic link is fooled.

Wrong---or `should be wrong', at least.

>Why was the system designed in a way that makes this use of make so 
>difficult?

It was not.

Although symbolic links do occupy an inode, and therefore have all the
information a `stat' operation can find, they are not normally supposed
to be examined by programs.  Indeed, it requires a special system call
(lstat()) to get this information: most system calls follow symlinks to
their ultimate destinations.  (The only other lookup operations that do
not follow symlinks are chown(), probably because the space used for the
target of the link is charged to the owner and thus this must be
changeable, and readlink(), for the obvious reason.  Removal operations,
of course, do not follow symlinks.  Normal creation operations do; opens
for creating with O_EXCL do not.)

Only a few programs---e.g., find (which must not follow symlinks since
they may not form a tree) and ls (which should show the name and target,
or whatnot)---have any business using lstat().  `Make' is not such a
program.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

alex@impch.imp.com (Alex Hanselmann) (08/02/90)

In article <1990Jul23.233044.2729@silma.com> aab@silma.UUCP () writes:
>I need to compare the modification times of two files in a bourne shell
>script. I would like to do this without writing C code.
>Machine is Sparcstation 1 running SunOS 4.03c
>
>Thus I need a function:
>
>newer file1 file2
>
>that returns 0 if file1 is newer than file2 else returns 1
>
>Can it be done?

yes here's the script for newer. It's work with the modification time.

--
#!/bin/sh
#newer file1 file2 (mode)
# returns 0 if file 1 is newer then file2 refered by mode (A/M/C (=> man ls)
# returns 1 if file 2 is newer then file1 refered by mode ...
# returns 2 on error


if [ $# -lt 2 -o $# -gt 3 ] ;then
	echo "error in usage: incorrect argc" 
	exit 2
fi

NMODE=''

if [ $# -eq 3 ] ; then
	case $3 in
	[Aa]) NMODE='u' ;;
	[Cc]) NMODE='c' ;;
	esac
fi


[ `ls -t$NMODE $1 $2 | line` = $1 ] && exit 0
exit 1
---

alex

andrew@alice.UUCP (Andrew Hume) (08/03/90)

	if this is true, then sun's make is broken (as it often is).
there is no reason why it should do an lstat rather than a stat to find
out the modifcation time.