Backslash36
Backslash36

Reputation: 805

How to exclude specific files with the tar command?

Let's assume I have the following directory structure

dir/
├── subdir
│   ├── dir
│   │   └── TODO.txt
│   └── TODO.txt
└── TODO.txt

I wish to bundle dir/ recursively into a tarball with the command tar on Linux, but I want to exclude the root TODO.txt. How can I specify this with a relative path ?

Attempt #1

tar -czf dir.tar.gz  dir/ --exclude='TODO.txt'

Doesn't work : it gets rid of every TODO.txt in the resulting tarball :

dir/
└── subdir
    └── dir

Attempt #2

tar -czf dir.tar.gz  dir/ --exclude='dir/TODO.txt'

This also fails, because the dir subdirectory is also matched by this pattern. The resulting tarball hence contains

dir/
└── subdir
    ├── dir
    └── TODO.txt

Is there any way I can specify exactly that I want to exclude the root TODO.txt with a relative path ?

Upvotes: 1

Views: 4169

Answers (2)

Raoul Steffen
Raoul Steffen

Reputation: 556

Instead of using dir/ to name your transfer, cd into dir, then name it as .. The folder name . will never appear later in any files path, so it serves as a robust anchor. Then use --transform=, to have the paths in the archive begin with dir/.

Demonstration

without filter:

$ tar -czf dir.tar.gz -v dir
dir/
dir/TODO.txt
dir/subdir/
dir/subdir/TODO.txt
dir/subdir/dir/
dir/subdir/dir/TODO.txt

cd into dir, name it as .:

$ tar -czf dir.tar.gz -v -C dir .
./
./TODO.txt
./subdir/
./subdir/TODO.txt
./subdir/dir/
./subdir/dir/TODO.txt

exclude, anchoring on .:

$ tar -czf dir.tar.gz -v -C dir --exclude='./TODO.txt' .
./
./subdir/
./subdir/TODO.txt
./subdir/dir/
./subdir/dir/TODO.txt

change . back to dir inside the archive (--show-transformed-names makes tar show the names as they go into the archive):

$ tar -czf dir.tar.gz -v -C dir --exclude='./TODO.txt' --transform='s/^\./dir/g' --show-transformed-names .
dir/
dir/subdir/
dir/subdir/TODO.txt
dir/subdir/dir/
dir/subdir/dir/TODO.txt

Upvotes: 2

Backslash36
Backslash36

Reputation: 805

From @arkascha 's answer :

find dir/ -type f | grep -v "^dir/TODO.txt" > files.txt

then

tar -czf dir.tar.gz -T files.txt

From the first line, there are 2 tricks to pay attention to :

  1. The -type f option. If not put, directories will be included in find's result. This is bad, because it would include each file as many times as their depth in the file hierarchy.
  2. The ^ in grep's regex : it ensures that we're excluding the pattern from the begining of the file hierarchy

Upvotes: 0

Related Questions