filter in "find" ignored when output fed to tar

To expand on what @cuonglm said, tar by default operates recursively. If you pass it a directory name, it will archive the contents of that directory.

You could modify your find command to return only the names of files, not directories...

find test/ -type f -not -path "*1*" -not -path "*2*" |
tar -czvf test.tar.gz --files-from -

You could instead use the --no-recursion flag to tar:

find test/ -not -path "*1*" -not -path "*2*" | 
tar -czvf test.tar.gz --no-recursion --files-from - 

Which results in:

test/
test/3/

The --no-recursion flag is specific to GNU tar. If you're using something else, consult the appropriate man page to see if there is a similar feature available.

Note that your find command will exclude files that contain 1 or 2 in the path as well as directories.


With GNU tar, you can also use the --exclude option to exclude files based on names.

$ tar --exclude "*1*" --exclude "*2*" -cvf foo.tar  test/
test/
test/3/

There's also -X or --exclude-from which takes a file from which to read the exclusion patterns.


Though as find -not -path "*1*", this will also exclude files whose names contain a 1 or 2. To only skip directories whose names match the pattern, use find -prune and tar --no-recursion:

$ touch test/3/blah.1
$ find test/ -type d \( -name "*1*" -o -name "*2*" \) -prune -o -print |
   tar cvf test.tar --files-from - --no-recursion
test/
test/3/
test/3/blah.1

(At least GNU tar and FreeBSD tar have --no-recursion)