How to combine the 'tar' command with 'find'
Note: See @Iain's answer for a somewhat more efficient solution.
Note that find
will call the -exec
action for every single file it finds.
If you run tar -cvf file.tar {}
for every single file find
outputs, this means you'll overwrite file.tar
every time, which explains why you end up with one archive left that only contains anaconda.storage.log
— it's the last file find
outputs.
Now, you actually want to append the files to the archive instead of creating it each time (this is what the -c
option does). So, use the following:
find var/log/ -iname "anaconda.*" -exec tar -rvf file.tar {} \;
The -r
option appends to the archive instead of recreating it every time.
Note: Replace -iname anaconda.*
with -iname "anaconda.*"
. The asterisk is a wildcard and can be expanded by your shell before find
even sees it. To prevent this expansion, wrap the argument in double quotes.
As for tar
removing leading /
: The archive should only contain relative file names. If you added files with a leading /
, they would be stored as absolute file names, literally meaning /var/…
on your computer, for example.
IIRC this is simply a precaution for tar
implementations other than GNU, and it's safer this way because you won't overwrite your actual data in /var/…
when you extract the archive if it contains relative filenames.
You can use something like:
find var/log -iname 'anaconda.*' -print0 | tar -cvf somefile.tar --null -T -
The -print0
and -T
work together to allow filenames with spaces newlines, etc. The final -
tells tar to read the input filenames from stdin.
Note that -print0
must come at the end of your statement, per this answer. Otherwise you will probably get more files than you expect.
Try this:
tar -cvf file.tar `find var/log/ -iname "anaconda.*"`
You were trying to use find
to -exec tar
. But the way the -exec
option works, it runs that command once for each matching file it finds, causing tar
to overwrite the tar file it produces each time. That's why you only ended up with the last one. Also, you need to put quotes around the pattern you specify to find
so that the shell doesn't expand it before passing it to find
.
Using command substitution with backticks (or using $(...)
notation if you prefer), the entire list of names produced by find
is pasted back onto the command line as arguments to tar
, causing it to write them all at once.
Question 1
Your command fails because tar
is taking each of the files found and archiving them into file.tar
. Each time it does so, it will overwrite the previously created file.tar
.
If what you want is one archive with all the files, then simply run tar
directly, there is no need for find
(and yes, this works for files with spaces in their names):
tar -vcf file.tar /var/log/anaconda*
Question 2
The two commands are completely different:
find var/log will search a directory called
var/log
which is a subdirectory of your current directory, it is equivalent tofind ./var/log
(notice the./
).find /var/log will search a directory called
/var/log
which is a subdirectory of the root,/
.
The leading /
message is from tar
, not find
. It means that it is removing the first /
of your file names to make absolute paths into relative. This means that the file from /var/log/anaconda.error
will be extracted to ./var/log/anaconda.error
when you untar the archive.
There are two ways -exec
can work. One way runs the command many times - once for each file; the other way runs the command once, including all the files as a list of parameters.
-
-exec tar -cvf file.tar {} ';'
runs thetar
command for each file, overwriting the archive each time. -
-exec tar -cvf file.tar {} '+'
runs thetar
command once, creating an archive of all the files found.