bug-bash
[Top][All Lists]
Advanced

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

Re: docs incorrectly mention pattern matching works like pathname expans


From: Robert Elz
Subject: Re: docs incorrectly mention pattern matching works like pathname expansion
Date: Fri, 16 Mar 2018 16:42:16 +0700

    Date:        Thu, 15 Mar 2018 22:52:24 +0000 (UTC)
    From:        Stormy <address@hidden>
    Message-ID:  <address@hidden>

  |  but there is no way to make it do pathname matching internally. (cd, ls, 
will surely do it,

No, they surely don't - the pathname expansion that you seem to see in them is
done in the shell before they run.   "find" (and a few other commands) does 
matching, but there are only a few like that.

What might make things clearer is that in the normal case (I think bash has 
mechanisms that extend this) pathname matching is just pattern matching
applied to each component of the path name, one at a time.

That is, when pathname expansion is done (and it is attempted on every
unquoted argument to every command, unless turned off by "set -f") it works
by separating the word into components at the /s and then doing matching
using the list of patterns created by this, starting at the first, matching 
against the current directory (or the root directory if the path started with 
'/') matching the patten from next component against the file names in
that directory - then as it proceeds along the path name components, it
looks in every directory already found by earlier matching.

Whether the actual implementation works exactly like that or not does
not matter - there are some optimisations that can be used to speed
things up, but conceptually that is what happens.

The pattern matching that happens is identical here as it is in case
statements - the '/' does not match as it is not there in the patterns that
are used in the pathname match - the slashed were used to separate the
word into the list of component patterns, and removed (and because no
directory entry can contain a '/' character, so inventing some method to
allow it would be pointless).

Other matching, such as in case statements, simply uses the pattern
word as the pattern, regardless of what characters (including / are in it)
and matches it against some other string, which also might have / chars
in it.   The matching is identical, here / is just the same as any other
ordinary character - it is only special in path names.

You're right that if you want to test to see if a string will match another
string, as if one is a pathname pattern, and the other is a potential
file name, then you have to write code to do that (it is not something that
most people ever need to do...)

But something based upon

fnmatch()
{
        local IFS PATTERN PATHNAME A -

        PATTERN="$1"
        PATHNAME="$2"
        
        set -f
        IFS=/
        set -- $PATTERN

        for A in $PATHNAME
        do
                [ $# -eq 0 ] && return 1

                case "$A" in
                $1)     ;;
                *)      return 1;;
                esac
                shift
        done
        [ $# -eq 0 ]
}

is a few less than 40 lines, and should be approximately what is wanted
(note this has not been tested much - it is just intended as a hint)
Also note that since this uses "local" and particularly "local -" it is not
even slightly portable (though more than one shell can run it.)

usage is:

        fnmatch pattern potential-pathname

where you will usually need to quote the pattern arg (at least) to
prevent pathname expansion from altering it.

The result is its exit status. (so it can be used like

        if fnmatch ...
        then
                ....
        fi

kre




reply via email to

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