Reputation: 805
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
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
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 :
-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.^
in grep
's regex : it ensures that we're excluding the pattern from the begining of the file hierarchyUpvotes: 0