Re: "And" extended matching operator

2012-12-04 Thread Irek Szczesniak
On Mon, Dec 3, 2012 at 7:48 PM, Dan Douglas  wrote:
> On Wednesday, November 28, 2012 07:23:17 PM Nikolai Kondrashov wrote:
>> @(a&!(b))
>
> This is the syntax ksh93 already uses. So far nobody else has adopted it, but
> the equivalent as you already mentioned is the transformation to:
>
> !(!(...)|!(...))
>
> It's just a matter of implementing it. Other handy matching features still
> missing are the non-greedy modifier for pattern-lists, arbitrary quantifiers,
> and grouping for patterns (already supported for ERE only with BASH_REMATCH,
> but there's no .sh.match equivalent.)

Well, before bash can implement a .sh.match equivalent it first must
support multidimensional arrays (.sh.match is a one-dimensional array
for ${s/} matches and a 2D array for ${s//} matches).

Irek



Re: Some globstar patterns produce duplicate entries and a null filename

2012-12-04 Thread Chet Ramey
On 12/1/12 10:41 AM, Ulf Magnusson wrote:
> GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)
> 
> Take the following example, assumed to be run in an empty directory:
> 
> $ mkdir a
> $ echo **
> a
> $ echo **/**
>  a a
> $ echo **/**/**
>  a a a
> 
> I would expect the result to be just 'a' in all cases.
> 
> You also get back a null filename, as shown by
> 
> $ for f in **/**/**; do echo "'$f'"; done
> ''
> 'a'
> 'a'
> 'a'

Thanks for the report.  This is definitely a problem.  It will be fixed
in the next version of bash, and may be released as a future patch.  I've
attached a patch for you to test; it fixes the problem for me without
introducing any new errors.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
*** ../bash-4.2-patched/lib/glob/glob.c	2012-07-14 15:53:13.0 -0400
--- lib/glob/glob.c	2012-12-04 21:03:07.0 -0500
***
*** 934,938 
--- 1075,1081 
  	{
  	  char **temp_results;
+ 	  int shouldbreak;
  
+ 	  shouldbreak = 0;
  	  /* XXX -- we've recursively scanned any directories resulting from
  	 a `**', so turn off the flag.  We turn it on again below if
***
*** 966,970 
  		 name to the results; we've already done it in glob_vector */
  	  if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
! 		array = temp_results;
  	  else
  		array = glob_dir_to_array (directories[i], temp_results, flags);
--- 1109,1144 
  		 name to the results; we've already done it in glob_vector */
  	  if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
! 		{
! 		  /* When do we remove null elements from temp_results?  And
! 		 how to avoid duplicate elements in the final result? */
! 		  /* If (dflags & GX_NULLDIR) glob_filename potentially left a
! 		 NULL placeholder in the temp results just in case
! 		 glob_vector/glob_dir_to_array did something with it, but
! 		 if it didn't, and we're not supposed to be passing them
! 		 through for some reason ((flags & GX_NULLDIR) == 0) we
! 		 need to remove all the NULL elements from the beginning
! 		 of TEMP_RESULTS. */
! 		  /* If we have a null directory name and ** as the filename,
! 		 we have just searched for everything from the current
! 		 directory on down. Break now (shouldbreak = 1) to avoid
! 		 duplicate entries in the final result. */
! #define NULL_PLACEHOLDER(x)	((x) && *(x) && **(x) == 0)
! 		  if ((dflags & GX_NULLDIR) && (flags & GX_NULLDIR) == 0 &&
! 			NULL_PLACEHOLDER (temp_results))
! #undef NULL_PLACEHOLDER
! 		{
! 		  register int i, n;
! 		  for (n = 0; temp_results[n] && *temp_results[n] == 0; n++)
! 			;
! 		  i = n;
! 		  do
! 			temp_results[i - n] = temp_results[i];
! 		  while (temp_results[i++] != 0);
! 		  array = temp_results;
! 		  shouldbreak = 1;
! 		}
! 	  else
! 		array = temp_results;
! 		}
  	  else
  		array = glob_dir_to_array (directories[i], temp_results, flags);
***
*** 987,990 
--- 1161,1169 
  	  if (array != temp_results)
  		free ((char *) array);
+ 	  else if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
+ 		free (temp_results);	/* expanding ** case above */
+ 
+ 	  if (shouldbreak)
+ 		break;
  	}
  	}