zip -x 'pattern': Matches path rather than file name

I am creating a backup of a folder tree, and trying to intelligently exclude swaths of files by path. I combed the zip man page to see if the file exclusion option -x 'pattern' matches by file name for file path. It's not very clear, but it seems that the -R option causes zip to match by file path in locating files to include. No such vague hint is provided in the descriptions of the -i or -x options. My tests of -x 'pattern' seems to indicate that it does exclude files based on matching by file path rather than file name:

# Bash command line example
$ mkdir -p TstDir/tstHHHdir
$ touch TstDir/tstHHHdir/file.c
$ zip -r test.zip TstDir -x '*HHH*'
updating: TstDir/ (stored 0%)

I am uncomfortable with guessing based on limited trials, as it's easy to be mistaken or somehow misinterpret.

Can anyway say definitively whether matching by file path is zip's default behaviour for its options? If so, then what is the difference between -r and -R options?


Solution 1:

The following empirically tests the the pattern matching behaviour of zip's options -x, -d, -r, and -R.

# Create test folders for -x and -d
mkdir -p TstDir/tstAAAsubdir \
         TstDir/tstBBBsubdir \
         TstDir/tstCCCsubdir \
         TstDir/tstDDDsubdir \
         TstDir/tstEEEsubdir

# Create test files for -x and -d
touch TstDir/tstAAAsubdir/fileA.c \
      TstDir/tstBBBsubdir/fileB.c \
      TstDir/tstCCCsubdir/fileC.c \
      TstDir/tstDDDsubdir/fileD.c \
      TstDir/tstEEEsubdir/fileE.c

# -x option matches by path
zip -rDy test.zip TstDir -x '*AAA*' '*BBB*'

   adding: TstDir/tstCCCsubdir/fileC.c (stored 0%)
   adding: TstDir/tstDDDsubdir/fileD.c (stored 0%)
   adding: TstDir/tstEEEsubdir/fileE.c (stored 0%)

# -d option matches by path
zip -d test.zip '*CCC*' '*DDD*'

   deleting: TstDir/tstCCCsubdir/fileC.c
   deleting: TstDir/tstDDDsubdir/fileD.c

#=================================================
# Create test folders for -r and -R
mkdir -p TestDir/testAAAdir \
         TestDir/testBBBdir

# Create test files for -r and -R
touch TestDir/testAAAdir/File.b \
      TestDir/testBBBdir/File.b \
      TestDir/testAAAdir/File.c \
      TestDir/testBBBdir/File.c
#-------------------------------------------------
# -r matches by file path

zip -r test.zip '*AAA*.c'

   updating: TestDir/testAAAdir/File.c (stored 0%)
#-------------------------------------------------
# -R doesn't match file path

zip -R test.zip '*AAA*.c'

   zip error: Nothing to do! (test.zip)
#-------------------------------------------------
# The well-known behaviour of -r to descend into
# the file/path specified, recursively zipping
# up files

zip -r test.zip TestDir

   updating: TestDir/testAAAdir/File.c (stored 0%)
   updating: TestDir/testBBBdir/File.c (stored 0%)
     adding: TestDir/ (stored 0%)
     adding: TestDir/testAAAdir/ (stored 0%)
     adding: TestDir/testAAAdir/File.b (stored 0%)
     adding: TestDir/testBBBdir/ (stored 0%)
     adding: TestDir/testBBBdir/File.b (stored 0%)
#-------------------------------------------------
# -R didn't match by path above, but does
# recursively descend into the specified folder and
# matches encountered files by file name

zip -R test.zip TestDir '*.c'

   updating: TestDir/testAAAdir/File.c (stored 0%)
   updating: TestDir/testBBBdir/File.c (stored 0%)
#-------------------------------------------------
# Even if the path pattern exists in the folder
# into which zip descends, the -R option *still*
# doesn't match by path -- at least, not treating
# the file separator as an ordinary file name
# character that matchable by "*"

zip -R test.zip TestDir '*AAA*.c'

   zip error: Nothing to do! (test.zip)
#-------------------------------------------------
# However, the -R option *does* match a path using
# what seems like Bash rules, where the file
# separator is not assumed to match "*"

zip -R test.zip TestDir '*AAA*/*.c'

   updating: TestDir/testAAAdir/File.c (stored 0%)
#-------------------------------------------------
# The -r option also seems to match by Bash rules,
# but this behaviour could be because it is a
# subset of the file path matching behaviour above

zip -r test.zip 'TestDir/*AAA*/*.c'

   updating: TestDir/testAAAdir/File.c (stored 0%)