Case-insensitive matching in bash - Again

Case-insensitive matching in bash - Again

Post by CV » Fri, 25 Feb 2005 23:22:26



I didn't get around to trying this until now, so
I continue here, in a new thread:

The question is still the same: How can I perform case-insensitive
string matching in bash without calling an external program such
as grep ?

...

Quote:>>>>But how can I make the matching case-insensitive ?

>>>shopt -s nocaseglob

>>Thanks. I think this must be what I had in mind from
>>before. Doesn't appear to work for me now though.
>>I am doing this in cygwin* at the moment, but will
>>give it a try in linux when I get around to it.

>>Cheers CV

>>* GNU bash, version 2.05b.0(1)-release (i686-pc-cygwin)
>>   CYGWIN_NT-5.1 <host> 1.5.12(0.116/4/2) 2004-11-10 08:34 \
>>   i686 unknown unknown Cygwin

> It should work for 'case' statement.

It doesn't, actually:

~$ ccc() { shopt -s nocaseglob; case $1 in *abc*) echo "abc found";; *) echo "not found";; esac; }
~$ ccc sdaabcvgasfdg                                                            
abc found
~$ ccc sdaAbcvgasfdg
not found
~$

According to the manpage nocaseglob works for filename expansion.
It doesn't say anything about string matching.

Regards CV

 
 
 

Case-insensitive matching in bash - Again

Post by Chris F.A. Johnso » Sat, 26 Feb 2005 00:34:30



> I didn't get around to trying this until now, so
> I continue here, in a new thread:

> The question is still the same: How can I perform case-insensitive
> string matching in bash without calling an external program such
> as grep ?

    It looks long, but this is still quicker than calling grep unless
    the pattern is longer than ~35 characters (YMMV).

ccc() ## Your function
{
    case $1 in
        *$_IPAT*) echo "$pat found";;
        *) echo "not found";;
    esac

Quote:}

_ocase() { ## Switch case of $1 (requires $upper and $lower to be defined)
    case $1 in
        [a-z]) idx=${lower%$1*}
               _OCASE=${upper:${#idx}:1}
               ;;
        [A-Z]) idx=${upper%$1*}
               _OCASE=${lower:${#idx}:1}
               ;;
         *) _OCASE=$1 ;;
    esac

Quote:}

_ipat() ## Create case-insensitive pattern from $1
{
    word=${1}
    _IPAT=

    while [ -n "$word" ]
    do
      the_rest=${word#?}
      first=${word%"$the_rest"}
      _ocase "$first"
      _IPAT=$_IPAT\[$first$_OCASE\]
      word=$the_rest
    done

Quote:}

lower=thequickbrownfxjmpsvlazydg
upper=THEQUICKBROWNFXJMPSVLAZYDG

str=$1
pat=$2
_ipat "$pat"
ccc "$str"

--
    Chris F.A. Johnson                  http://cfaj.freeshell.org/shell
    ===================================================================
    My code (if any) in this post is copyright 2005, Chris F.A. Johnson
    and may be copied under the terms of the GNU General Public License

 
 
 

Case-insensitive matching in bash - Again

Post by Icarus Sparr » Sat, 26 Feb 2005 01:29:12



> I didn't get around to trying this until now, so
> I continue here, in a new thread:

> The question is still the same: How can I perform case-insensitive
> string matching in bash without calling an external program such
> as grep ?


> ...
>>>>>But how can I make the matching case-insensitive ?

>>>>shopt -s nocaseglob

>>>Thanks. I think this must be what I had in mind from
>>>before. Doesn't appear to work for me now though.
>>>I am doing this in cygwin* at the moment, but will
>>>give it a try in linux when I get around to it.

>>>Cheers CV

>>>* GNU bash, version 2.05b.0(1)-release (i686-pc-cygwin)
>>>   CYGWIN_NT-5.1 <host> 1.5.12(0.116/4/2) 2004-11-10 08:34 \
>>>   i686 unknown unknown Cygwin

>> It should work for 'case' statement.

> It doesn't, actually:

> ~$ ccc() { shopt -s nocaseglob; case $1 in *abc*) echo "abc found";; *) echo "not found";; esac; }
> ~$ ccc sdaabcvgasfdg                                                            
> abc found
> ~$ ccc sdaAbcvgasfdg
> not found
> ~$

> According to the manpage nocaseglob works for filename expansion.
> It doesn't say anything about string matching.

If you are willing to switch to regular expressions, then the manual
tells you that the =~ operator will obey the nocaseglob for strings

ccc(){
        # arrange for nocaseglob to be the same before and after
        # this routine
        setter=-u
        if shopt -q nocaseglob
        then
                setter=-s
        fi
        shopt -s nocaseglob
        # Do the compare in a case insensitive manner
        if [[ $1 =~ ".*abc.*" ]]
        then
                shopt $setter nocaseglob
                return 0
        else
                shopt $setter nocaseglob
                return 1
        fi

- Show quoted text -

Quote:}

 
 
 

Case-insensitive matching in bash - Again

Post by William Par » Sat, 26 Feb 2005 01:35:39



> I didn't get around to trying this until now, so
> I continue here, in a new thread:

> The question is still the same: How can I perform case-insensitive
> string matching in bash without calling an external program such
> as grep ?

> > It should work for 'case' statement.
...
> It doesn't, actually:
...
> According to the manpage nocaseglob works for filename expansion.
> It doesn't say anything about string matching.

Yeah, manpage is a bit ambiguous.  'nocaseglob' does not work for 'case'
or '[[...]]'.  If you don't want to use external program, then you can
apply my patch for Bash (http://freshmeat.net/projects/bashdiff/).

Then, you can use regex in 'case' statement, like
    shopt -s nocaseglob
    case Abc123 in
        abc)) echo found abc ;;
    esac
where '))' denotes regex instead of the usual glob.  There is
comprehensive helpfile, so
    help case

--

Slackware Linux -- because I can type.

 
 
 

Case-insensitive matching in bash - Again

Post by CV » Sat, 26 Feb 2005 05:08:09



> If you are willing to switch to regular expressions, then the manual
> tells you that the =~ operator will obey the nocaseglob for strings

> ccc(){
...
>         shopt -s nocaseglob
>    # Do the compare in a case insensitive manner
>         if [[ $1 =~ ".*abc.*" ]]
>         then

...

That would be nice, but my bash version (version 2.05b.0(1)-release
(i686-pc-cygwin)) does not seem to know about this feature. It is
not mentioned in the man-page and the "=~" generates an error.

I suppose what you describe here will be in some later version
of bash (?)

Thanks all the same.
CV

 
 
 

Case-insensitive matching in bash - Again

Post by CV » Sun, 27 Feb 2005 00:48:20



>     It looks long, but this is still quicker than calling grep unless
>     the pattern is longer than ~35 characters (YMMV).

Nifty script, Chris.

Yes, I can easily believe this is faster than calling grep, especially
in cases where you only need to generate the pattern once, but the actual
string comparison is performed a large number of times.

Still, if one needs to go to these lengths maybe it is better to
go for perl or something else for this.

Thanks to all who replied.
CV

 
 
 

Case-insensitive matching in bash - Again

Post by Chris F.A. Johnso » Sun, 27 Feb 2005 00:56:46




>>     It looks long, but this is still quicker than calling grep unless
>>     the pattern is longer than ~35 characters (YMMV).

> Nifty script, Chris.

> Yes, I can easily believe this is faster than calling grep, especially
> in cases where you only need to generate the pattern once, but the actual
> string comparison is performed a large number of times.

   Then you'll save time for each call, make it cumulatively MUCH
   faster, especially on short strings.

Quote:> Still, if one needs to go to these lengths

   What "lengths"? It's written; just put it in a file and source it
   whenever you need it.

Quote:> maybe it is better to go for perl or something else for this.

   "Something else", perhaps.

--
    Chris F.A. Johnson                  http://cfaj.freeshell.org/shell
    ===================================================================
    My code (if any) in this post is copyright 2005, Chris F.A. Johnson
    and may be copied under the terms of the GNU General Public License

 
 
 

Case-insensitive matching in bash - Again

Post by CV » Sun, 27 Feb 2005 04:40:04



>    What "lengths"? It's written; just put it in a file and source it
>    whenever you need it.

Readability, maintainability. Much as I admire the elegant bit of
wizardry that code is, it is not so obvious to see at a glance how
it works.

I like to be able to come back after a few months and easily
understand how the bits and pieces fit together, perhaps to
modify the code, perhaps to base some new design on it.

Cheers CV

 
 
 

1. Case-insensitive matching of substring in bash ?

Hello,
Detecting whether "substring" is found in $string is easy
enough in bash:

[ -z "${string##*substring*}" ] && {
   <do something>;

But how can I make the matching case-insensitive ?

Best I've come up with so far is using grep:

[ -n "$(echo $string | grep -i "substring")" ] && ...

... but I have a strong feeling there must be a simpler
and quicker way, without calling an external program.

I think I vaguely remember having done this in bash in
the past. But it seems I cant quite get it together
this time, and I can also not find anything useful
about this in the man page.

Am I missing something obvious ?

CV

2. Anyone using Microcom parallel modem

3. awk case-insensitive pattern matching

4. Problems w/new G4-400

5. case-insensitive pattern matching in awk

6. Problem with icons, etc. looking chopped up

7. case-insensitive file system with Apache being case-sensitive.

8. bug in sh ?

9. shell script question - matching case insensitive

10. Netscape Server: Case Insensitive path match?

11. case insensitive tab completion in bash?

12. Bash, case insensitive globbing and Solaris 8

13. how to make regexp case-insensitive using sed