[comp.unix.wizards] impossible problem for find

roy@phri.UUCP (Roy Smith) (04/24/87)

	A user posed a problem which I can't solve.  She wants to find all
the files named *refs which are newer than a file called INDEX in the same
directory.  Thus she wants to know if any of ./x/foorefs, ./x/barrefs or
./x/bazrefs is newer than ./x/INDEX, and if ./y/z/refs is newer than
./y/z/INDEX, etc.  I can't think of how to do this with find, or even any
combination of find and any other standard tools.  We're running MtXinu
4.3BSD/NFS on a Vax and Sun-3.1 on some Sun-3's.

	The obvious

% find . "*refs" -newer INDEX -print

finds *refs files which are newer than INDEX in the directory in which I
ran the find.  This is not, unfortunately, what I need.

	The Sun version of make has a -q option which I could use to do
something like

% find . -name INDEX -exec make -q INDEX ';'

but this will only work on the Suns, and there is still the problem of how
to phrase the Makefiles and where to put them.  Of course, if the MtXinu
NFS support worked better I would contemplate running this on a Sun CPU
mounting the Vax disk, but it doesn't, so I won't.

	I could envision something horrible along the lines of

% find . -type d -exec find '{}' -type d -prune -name '"*refs"' \
-newer INDEX -exec pwd -print '";"' ';'

but I no longer do the type of drugs required to seriously contemplate
doing that.  I havn't wasted the time to get the exact syntax of the above
correct so please don't bother flaming me about messing up the double layer
of quotes or some other silly detail.  It was meant as a general idea, not
a finished product.  Note that you need the "-exec pwd" in the inner-level
find because all "-print" will say is "./foorefs" which isn't useful.

	Another hair-brained (a cross between hairy and brain-damaged?)
idea centers around doing "ls -lt INDEX *refs" and checking to see that the
first output line contains (or actually doesn't contain) INDEX, perhaps by
piping it through "head -1 | grep INDEX".  This gives (roughly)

% find . -type d \
-exec sh -c 'ls -lt {}/INDEX {}/*refs | head -1 | egrep -vs INDEX' ';' \
-print

which is also too sick to think about doing, let alone explaining to a
non-wizard.  Besides, I wouldn't count on the "sh -c" to properly pass back
the exit status of the pipeline (earlier Berkeley versions of sh did this
wrong; I have no idea if the 4.3 version is fixed or not), and you run into
problems if the sh dies because the *refs expansion doesn't work in a
particular directory.

	Is there really no easy way to do this?
-- 
Roy Smith, {allegra,cmcl2,philabs}!phri!roy
System Administrator, Public Health Research Institute
455 First Avenue, New York, NY 10016

"you can't spell deoxyribonucleic without unix!"

mkhaw@teknowledge-vaxc.ARPA (Michael Khaw) (04/24/87)

In article <2645@phri.UUCP> roy@phri.UUCP (Roy Smith) writes:
>
>	A user posed a problem which I can't solve.  She wants to find all
>the files named *refs which are newer than a file called INDEX in the same
>directory.  Thus she wants to know if any of ./x/foorefs, ./x/barrefs or
>./x/bazrefs is newer than ./x/INDEX, and if ./y/z/refs is newer than
>./y/z/INDEX, etc.  I can't think of how to do this with find, or even any

How about (csh)

	% foreach dir (x y)	# `pwd` == parent of x and y
	?	find $dir -name '*refs' -newer $dir/INDEX -print
	? end

Mike Khaw
-- 
internet:  mkhaw@teknowledge-vaxc.arpa
usenet:	   {hplabs|sun|ucbvax|decwrl|sri-unix}!mkhaw%teknowledge-vaxc.arpa
USnail:	   Teknowledge Inc, 1850 Embarcadero Rd, POB 10119, Palo Alto, CA 94303

trent@cit-vax.Caltech.Edu (Ray Trent) (04/24/87)

In article <2645@phri.UUCP> roy@phri.UUCP (Roy Smith) writes:
>
>	A user posed a problem which I can't solve.  She wants to find all
>the files named *refs which are newer than a file called INDEX in the same
>directory.  Thus she wants to know if any of ./x/foorefs, ./x/barrefs or

Here's a cute solution:

Place the following into the Makefile for each of the directories:

---start of new lines---
INDEX : *refs
	echo "`pwd`: "; ls $?
---end of new lines---

and execute:

  find . -name INDEX -exec make -s INDEX \;

I just tried this and it does exactly what you requested. The -name
INDEX part of the find command is so that make doesn't get executed in
directories not containing an INDEX. The -s option on make causes the
output command not to be echoed. The $? in the output command in the
Makefile refers to all prerequitsites that are not up to date. 

This way of doing it has the advantage that you can format the output
pretty much any way you want to by changing the command line in the
Makefile. 

Remember, you too can use make for *anything*.

<snicker, snicker>
-- 
<this space for rent>
					../ray\..
 (trent@csvax.caltech.edu, rat@caltech.bitnet, ...seismo!cit-vax!trent)

rmg@mips.UUCP (Richard M. Geiger) (04/25/87)

In article <2645@phri.UUCP> roy@phri.UUCP (Roy Smith) writes:
>
>	A user posed a problem which I can't solve.  She wants to find all
>the files named *refs which are newer than a file called INDEX in the same
>directory.  Thus she wants to know if any of ./x/foorefs, ./x/barrefs or
>./x/bazrefs is newer than ./x/INDEX, and if ./y/z/refs is newer than
>./y/z/INDEX, etc.  I can't think of how to do this with find, or even any
>combination of find and any other standard tools.  We're running MtXinu
>4.3BSD/NFS on a Vax and Sun-3.1 on some Sun-3's.

Seems like you should be able to skin this cat with something like this...

a script, /user/rmg/bin/sinceindex:

  #!/bin/sh
  echo ===== "$1" =====
  cd "$1"
  ls -t *refs INDEX 2>/dev/null | sed -n -e '/^INDEX$/
  p'

and a find command:

  find . -type d -exec /user/rmg/bin/sinceindex {} \;

This seems to work. 

I fiddled for a bit with getting it all on one command line, (to keep from
having to have the script), but ran out of patience. I expect it could be
done without the script.

-- 
- Rich Geiger
{decvax,ucbvax,ihnp4}!decwrl!mips!rmg
MIPS Computer Systems, 930 E. Arques, Sunnyvale, CA 94086
(408) 720-1700 x308 [Day Job]  (408) 739-7911 [home]

chris@mimsy.UUCP (Chris Torek) (04/25/87)

In article <2645@phri.UUCP> roy@phri.UUCP (Roy Smith) writes:
>[problem:] find all the files named *refs which are newer than a
>file called INDEX in the same directory [as the *refs files].

If you have the `newer' program, this is easy: use -exec and a
short script that runs newer on the given file and the equivalent
INDEX file.  Without newer, the most efficient way to tackle this
is, probably, to first list all the `*refs' files with directories:

	find . -name \*refs -print |

Break up the result by directory name:

	awk -F/ '{
		dir = substr($0, 1, length($0) - length($NF));
		if (dir != last) {
			if (any)
				print "/shazam";
			any = 0;
		} else {
			if (any == 0) {
				any = 1;
				print "testthem " dir " << \\/shazam"
			}
			print $NF
		}
	}' | sh

The `testthem' script then looks something like this:

	cd $1
	if [ ! -f INDEX ]; then
		echo "$1: no INDEX file"
		cat		# list them all
		exit 1
	fi
	echo $1
	find `cat` -newer INDEX -print

and of course you can play games with formatting.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!mimsy!chris	ARPA/CSNet:	chris@mimsy.umd.edu

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/26/87)

In article <6454@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>If you have the `newer' program, ...

/*
	newer -- test file modification dates

	last edit:	86/03/30	D A Gwyn
*/
#ifndef lint
static char	SCCS_ID[] = "@(#)newer.c	1.1";
#endif

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

#define	EXIT	_exit			/* non-STDIO exit(), if available */

#define	STDERR	2			/* standard error file descriptor */

extern void	EXIT();
extern int	stat(), write();

main( argc, argv )
	int			argc;
	char			*argv[];
	{
	static char		usage[] = "Usage: newer file1 file2\n";
	static struct stat	file1;	/* file1 statistics */
	static struct stat	file2;	/* file2 statistics */

	if ( argc != 3 )
		{			/* wrong number of arguments */
		(void)write( STDERR, usage, sizeof usage - 1 );
		EXIT( 3 );
		}

	if ( stat( argv[1], &file1 ) != 0 )
		EXIT( 2 );		/* file1 doesn't exist */

	if ( stat( argv[2], &file2 ) != 0 )
		EXIT( 0 );		/* file2 doesn't exist */

#ifdef lint
	return file1.st_mtime < file2.st_mtime ? 1 : 0;
#else
	EXIT( file1.st_mtime < file2.st_mtime ? 1 : 0 );
#endif
	}

rbj@icst-cmr.arpa (Root Boy Jim) (04/27/87)

   Without newer, the most efficient way to tackle this
   is, probably, to first list all the `*refs' files with directories:

	   find . -name \*refs -print | torAWK-script

Except that it might be worth solving the smaller problem first.
First find only the directorys containing an INDEX, then figure out
what *refs are out of date and what to do with them.

Of course if you assume that in no INDEX exists that all the *refs
are out of date, as make would, it makes no difference.


	(Root Boy) Jim "Just Say Yes" Cottrell	<rbj@icst-cmr.arpa>
	I always have fun because I'm out of my mind!!!

davidsen@steinmetz.steinmetz.UUCP (William E. Davidsen Jr) (04/29/87)

In article <2645@phri.UUCP> roy@phri.UUCP (Roy Smith) writes:
>
>	A user posed a problem which I can't solve.  She wants to find all
>the files named *refs which are newer than a file called INDEX in the same
>directory.  Thus she wants to know if any of ./x/foorefs, ./x/barrefs or
>./x/bazrefs is newer than ./x/INDEX, and if ./y/z/refs is newer than
>./y/z/INDEX, etc.  I can't think of how to do this with find, or even any
>combination of find and any other standard tools.  We're running MtXinu
>4.3BSD/NFS on a Vax and Sun-3.1 on some Sun-3's.

After looking at some of the solutions to this, I decided that
my first thought was no more confusing and used something we all
have, the Bourne shell.

 $ find . -type d -print |
 > while read dirname
 > do
 >   find $dirname -name '*refs' -newer $dirname/INDEX -print
 > done

Note that if you don't escape the "*refs" as some of the
suggested solutions have (not) done, and you have a matching
file in the current directory, you will get filename expansion
and the find will fail.
-- 
bill davidsen			sixhub \	ARPA: wedu@ge-crd.arpa
      ihnp4!seismo!rochester!steinmetz ->  crdos1!davidsen
				chinet /
"Stupidity, like virtue, is its own reward"

karl@haddock.UUCP (Karl Heuer) (04/29/87)

In article <5797@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn) writes:
[source for program "newer", ending with]
>#ifdef lint
>	return file1.st_mtime < file2.st_mtime ? 1 : 0;
>#else
>	EXIT( file1.st_mtime < file2.st_mtime ? 1 : 0 );
>#endif

I don't mean to flame the author's style, but what's wrong with
	EXIT( file1.st_mtime < file2.st_mtime ? 1 : 0 );
	/* NOTREACHED */
?  That's what the lintpragma is for.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

jfh@killer.UUCP (John Haugh) (04/30/87)

That ought to do the trick.  '*refs' was the name of the files you were
looking for.  Find(1) does the file name matching itself, so you want to
pass the pattern, not the expansion to find(1).

- John.

"You can't spell Fred without Federalism" -- John "Fred" Haugh II.

tim@ism780c.UUCP (Tim Smith) (05/09/87)

If you are not going to do something a lot, it is sometimes faster
to just write a shell script rather than try to figure out exactly
which tools are right for the job.  In this example, the following
would work:

	$ find . -type d | dodir

where dodir is the following shell script:

	#!/bin/sh
	BASE=`pwd`
	while read DIR
	do
		cd $BASE
		cd $DIR
		if [ -r INDEX ]
		then
			mkdir TEMP.$$
			ln *xrefs TEMP.$$
			ln INDEX TEMP.$$
			cd TEMP.$$
			if ls -lt | sed 2q | fgrep INDEX > /dev/null 2>&1
			then
				#
				# Get here if INDEX is newer than
				# all the refs files
				#
			else
				#
				# Get here if some ref files are newer
				# than INDEX
				#
			fi
			cd ..
			rm -rf TEMP.$$
		fi
	done

Ok, I admit it is a kludge, but it works!
-- 
Tim Smith			"Froh wie seine Sonnen fliegen
sdcrdcf!ism780c!tim		 Durch des Himmels praecht'gen Plan,
				 Laufet, Brueder, eure Bahn,
				 Freudig wie ein Held zum Siegen"