6

I have the following directory structure:

test/
test/1/
test/foo2bar/
test/3/

I want to compress directory "test" excluding everything which is in subdirectories (depth not predefined), which include strings "1" or "2" in them. In bash shell, i want to use find and feed its output to tar. I first test find:

find test/ -not -path "*1*" -not -path "*2*"

Output:

test/
test/3

Great. So i combine it with tar:

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

Output:

test/
test/3/
test/1/
test/foo2bar/
test/3/

Indeed, both "test/1" and "test/foo2bar" are present in the archive. Why were these arguments passed to tar, if they were not supposed to be present in find output?

  • 6
    they are subdirectories of test/, so were archived because test/ was archived. – cuonglm Apr 7 '17 at 11:56
  • then i don't quite get how tar works.. Does it mean that first "test/" gets archived, including all its contents, then "test/3/", replacing the "test/3/" which was already included in the archive when compressing "test/"? – InternazionalIV Apr 7 '17 at 12:23
  • @InternazionalIV, They both get stored! You get two copies of the file or directory in the archive. You can check it with zcat test.tar.gz | strings. – ilkkachu Apr 7 '17 at 12:56
11

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.

  • One issue with listing only file names to tar is that the metadata for the directories (i.e. permissions) will not be saved. Extracting the archive will create them with default permissions. – ilkkachu Apr 8 '17 at 9:04
  • That's true, and why I provided the second option as well. – larsks Apr 8 '17 at 13:25
6

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)

  • That would cause it to ignore files like test/manpage.1 – David Conrad Apr 8 '17 at 7:23
  • 1
    @DavidConrad, like the original find -not -path. Good point though. – ilkkachu Apr 8 '17 at 8:58

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.