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 to find ./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 the tar command for each file, overwriting the archive each time.
  • -exec tar -cvf file.tar {} '+' runs the tar command once, creating an archive of all the files found.