0

In a higher-level programming language I am working on writing a wildcardMatch(input, pattern) function that I want to work exactly like the glob matching in Unix.

To do this I have been using property-based testing to generate random input and test it against my implementation and the Unix implementation and then comparing that their return values are the same.

My problem is that I don't trust my simple Unix helper script:

#!/bin/bash

## Created for development/testing
##
## Example Usage:
##  ./wildcard_test.sh "foobar" "fooba*"

string=$1
pattern=$2

if [[ $string == $pattern ]]; then
  echo 0
  exit 0
else
  echo 1
  exit 1
fi

Everything was working fine until I learned that the expansion would happen before the script actually runs:

./wildcart_test.sh "foo" "???"

In that example, the question marks will be expanded to actually match other files in that directory causing the == comparison to fail. In this case it was expanding to lib, for example.


Is there a better way to test glob matching?

  • 1
    If you ran your script with bash and in exactly the way you show, then the ??? pattern would not be expanded to any existing filenames in the current directory. Can you show some sort of transcript of this actually happening? – Kusalananda Dec 9 '19 at 16:41
  • Oh, I think I have confused myself a little bit - I was simply adding echo $pattern before the comparison and there it was outputting lib, but it seems that the comparison actually did succeed. – TylerAndFriends Dec 9 '19 at 16:45
  • Yes, the unquoted $pattern would be causing globbing to occur. Do look at Stéphane Chazelas' answer for a more portable test though. – Kusalananda Dec 9 '19 at 16:47
1

No,

./wildcart_test.sh "foo" "???"

is fine as that ??? is quoted, so not expanded by your shell. Note however that the \, $ and ` characters are still special within double quotes. You may want to use single quotes, inside which no character is special (in Bourne-like shells).

One thing you could do here though is remove the bash dependency and do it with standard sh syntax:

#! /bin/sh -
subject=${1?No subject} pattern=${2?No pattern}
case $subject in
  ($pattern) echo 1; true;;
  (*)        echo 0; false;;
esac

Note that while a 0 exit status means true, it's more customary to use a 0 number for false and non-zero for true.

Note however that with sh, to be portable, [^x] needs to be written [!x] as [^x] is still not standard.

And whether \ in $pattern is treated specially by the pattern matching code also depends on the implementation and version. that-script '\foo' '\*' may return false on some and true on others. Same forthat-script '*' '\*'.

To match on a literal backslash, use that-script '\foo' '[\\]*'. To match on a wildcard character (?, *, [), use that-script '*?[' '[*][?][[]'. Also beware of a bug/misfeature in the Bourne shell and its descendants (ksh88, ksh93): both that-script a '[a]' and that-script '[a]' '[a]' would return true on systems where /bin/sh is based on AT&T ksh.

| improve this answer | |
  • I think I am getting myself confused about expansion because I am trying to solve debug why the following case returns "no match": ./wildcart_test.sh "\\" "\\" I started adding echo statements and in those statements the expansion was happening. I am still unsure why the double backslashes do not match. – TylerAndFriends Dec 9 '19 at 16:49
  • @TylerAndFriends try '\' '\\' or "\\" "\\\\" – Kusalananda Dec 9 '19 at 16:51
  • So the input is interpreted literally while the pattern needs to be escaped? – TylerAndFriends Dec 9 '19 at 16:56
  • 1
    @TylerAndFriends, I'm not sure what you mean, but see if the later edits help – Stéphane Chazelas Dec 9 '19 at 17:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.