bug-findutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RFC: "-contains" option


From: Eddie Kohler
Subject: RFC: "-contains" option
Date: Sat, 21 Feb 2009 10:20:04 -0800
User-agent: Thunderbird 2.0.0.19 (X11/20090105)

Hi,

I frequently use "find" to search collections of files while pruning certain
directories.  However, I'd often like to prune build directories and the like,
and these don't have consistent names.

One solution is to prune directories that contain a file named ".find-ignore".
This can be coded up with, e.g, "-execdir test -e .find-ignore \; -prune".
Unfortunately, this makes find much slower -- on the relevant directory tree,
"find . -type d , -true" takes 1.44s, while "find . \( -type d -a -execdir
test -e .find-ignore \; \) , -true" takes 98.53s.

The patch below adds a "-contains NAME" test to find.  The test is true if the
current filename is a directory, and that directory contains a file named
NAME.  I wonder if it is worth including, or if anyone has comments.  (The
patch doesn't yet update the texinfo.)

Thanks,
Eddie Kohler


diff -ru findutils-4.2.33/find/defs.h findutils-4.2.33-p/find/defs.h
--- findutils-4.2.33/find/defs.h        2007-12-08 06:00:45.000000000 -0800
+++ findutils-4.2.33-p/find/defs.h      2009-02-21 09:09:33.000000000 -0800
@@ -435,6 +435,7 @@
 boolean pred_cmin PARAMS((char *pathname, struct stat *stat_buf, struct 
predicate *pred_ptr));
 boolean pred_cnewer PARAMS((char *pathname, struct stat *stat_buf, struct 
predicate *pred_ptr));
 boolean pred_comma PARAMS((char *pathname, struct stat *stat_buf, struct 
predicate *pred_ptr));
+boolean pred_contains PARAMS((char *pathname, struct stat *stat_buf, struct 
predicate *pred_ptr));
 boolean pred_ctime PARAMS((char *pathname, struct stat *stat_buf, struct 
predicate *pred_ptr));
 boolean pred_delete PARAMS((char *pathname, struct stat *stat_buf, struct 
predicate *pred_ptr));
 boolean pred_empty PARAMS((char *pathname, struct stat *stat_buf, struct 
predicate *pred_ptr));
diff -ru findutils-4.2.33/find/find.1 findutils-4.2.33-p/find/find.1
--- findutils-4.2.33/find/find.1        2007-04-15 12:04:34.000000000 -0700
+++ findutils-4.2.33-p/find/find.1      2009-02-21 09:32:26.000000000 -0800
@@ -260,6 +260,8 @@
 \-L option is in effect, the status-change time of the file it points
 to is always used.

+.IP "\-contains \fIname\fR"
+File is a directory and contains a file named \fIname\fR.
 .IP "\-ctime \fIn\fR"
 File's status was last changed \fIn\fR*24 hours ago.
 See the comments for
diff -ru findutils-4.2.33/find/parser.c findutils-4.2.33-p/find/parser.c
--- findutils-4.2.33/find/parser.c      2007-12-08 06:00:47.000000000 -0800
+++ findutils-4.2.33-p/find/parser.c    2009-02-21 09:33:19.000000000 -0800
@@ -83,6 +83,7 @@
 static boolean parse_cmin          PARAMS((const struct parser_table*, char 
*argv[], int *arg_ptr));
 static boolean parse_cnewer        PARAMS((const struct parser_table*, char 
*argv[], int *arg_ptr));
 static boolean parse_comma         PARAMS((const struct parser_table*, char 
*argv[], int *arg_ptr));
+static boolean parse_contains      PARAMS((const struct parser_table*, char 
*argv[], int *arg_ptr));
 static boolean parse_ctime         PARAMS((const struct parser_table*, char 
*argv[], int *arg_ptr));
 static boolean parse_daystart      PARAMS((const struct parser_table*, char 
*argv[], int *arg_ptr));
 static boolean parse_delete        PARAMS((const struct parser_table*, char 
*argv[], int *arg_ptr));
@@ -157,6 +158,7 @@
 static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct 
parser_table *entry, int regex_options));
 static boolean insert_fprintf PARAMS((FILE *fp, const struct parser_table 
*entry, PRED_FUNC func, char *argv[], int *arg_ptr));

+static boolean check_name_arg PARAMS((const char *pred, const char *arg));
 static struct segment **make_segment PARAMS((struct segment **segment, char 
*format, int len, int kind));
 static boolean insert_exec_ok PARAMS((const char *action, const struct 
parser_table *entry, char *argv[], int *arg_ptr));
 static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum 
comparison_type *comp_type));
@@ -213,6 +215,7 @@
   PARSE_TEST       ("atime",                 atime),
   PARSE_TEST       ("cmin",                  cmin),       /* GNU */
   PARSE_TEST       ("cnewer",                cnewer),             /* GNU */
+  PARSE_TEST       ("contains",              contains),
   PARSE_TEST       ("ctime",                 ctime),
   PARSE_POSOPT     ("daystart",              daystart),           /* GNU */
   PARSE_ACTION     ("delete",                delete), /* GNU, Mac OS, FreeBSD 
*/
@@ -546,6 +549,24 @@
 }

 static boolean
+parse_contains (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+  struct predicate *our_pred;
+
+  if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+    return false;
+  if (!check_name_arg("-contains", argv[*arg_ptr]))
+    return false;
+
+  our_pred = insert_primary (entry);
+  our_pred->need_stat = false;
+  our_pred->need_type = true;
+  our_pred->args.str = argv[*arg_ptr];
+  (*arg_ptr)++;
+  return true;
+}
+
+static boolean
 parse_ctime (const struct parser_table* entry, char **argv, int *arg_ptr)
 {
   return insert_time (argv, arg_ptr, entry, pred_ctime);
@@ -793,11 +814,11 @@
       --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
   puts (_("\
 tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
-      -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
-      -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex 
PATTERN\n\
-      -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
+      -cnewer FILE -contains NAME -ctime N -empty -false -fstype TYPE -gid N\n\
+      -group NAME -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN\n\
+      -iregex PATTERN -links N -lname PATTERN -mmin N -mtime N -name 
PATTERN"));
   puts (_("\
-      -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
+      -newer FILE -nouser -nogroup -path PATTERN -perm [+-]MODE -regex 
PATTERN\n\
       -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
       -used N -user NAME -xtype [bcdpfls]\n"));
   puts (_("\
diff -ru findutils-4.2.33/find/pred.c findutils-4.2.33-p/find/pred.c
--- findutils-4.2.33/find/pred.c        2007-12-08 06:00:47.000000000 -0800
+++ findutils-4.2.33-p/find/pred.c      2009-02-21 09:29:52.000000000 -0800
@@ -171,6 +171,7 @@
   {pred_amin, "cmin    "},
   {pred_cnewer, "cnewer  "},
   {pred_comma, ",       "},
+  {pred_contains, "contains "},
   {pred_ctime, "ctime   "},
   {pred_delete, "delete  "},
   {pred_empty, "empty   "},
@@ -376,6 +377,38 @@
 }

 boolean
+pred_contains (char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
+{
+  mode_t mode;
+  char *fn;
+  struct stat contained;
+  int r;
+
+  assert(state.have_type);
+  assert(state.type != 0);
+
+  (void) pathname;
+
+  if (state.have_stat)
+     mode = stat_buf->st_mode;
+  else
+     mode = state.type;
+
+  if (!S_ISDIR (mode))
+    return (false);
+
+  fn = (char *) xmalloc (strlen(state.rel_pathname) + 
strlen(pred_ptr->args.str) + 2);
+  if (!fn)
+    return (false);
+
+  sprintf (fn, "%s/%s", state.rel_pathname, pred_ptr->args.str);
+  r = lstat (fn, &contained);
+
+  free (fn);
+  return (r == 0 ? true : false);
+}
+
+boolean
 pred_ctime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
 {
   (void) &pathname;





reply via email to

[Prev in Thread] Current Thread [Next in Thread]