I want to create a tar archive in a different directory rather than the current directory.
I tried this command:
tar czf file.tar.gz file1 -C /var/www/
but it creates the archive in the current directory. Why?
tar
I want to create a tar archive in a different directory rather than the current directory.
I tried this command:
tar czf file.tar.gz file1 -C /var/www/
but it creates the archive in the current directory. Why?
You posted in a comment that you are working on a Mac OS X system. This is an important clue to the purpose of these ._*
files.
These ._*
archive entries are chunks of AppleDouble data that contain the extra information associated with the corresponding file (the one without the ._
prefix). They are generated by the Mac OS X–specific copyfile(3) family of functions. The AppleDouble blobs store access control data (ACLs) and extended attributes (commonly, Finder flags and “resource forks”, but xattrs can be used to store any kind of data).
The system-supplied Mac OS X archive tools (bsdtar
(also symlinked as tar
), gnutar
, and pax
) will generate a ._*
archive member for any file that has any extended information associated with it; in “unarchive” mode, they will also decode those archive members and apply the resulting extended information to the associated file. This creates a “full fidelity” archive for use on Mac OS X systems by preserving and later extracting all the information that the HFS+ filesystem can store.
The corresponding archive tools on other systems do not know to give special handling to these ._*
files, so they are unpacked as normal files. Since such files are fairly useless on other systems, they are often seen as “junk files”. Correspondingly, if a non–Mac OS X system generates an archive that includes normal files that start with ._
, the Mac OS X unarchiving tools will try to decode those files as extended information.
There is, however an undocumented(?) way to make the system-supplied Mac OS X archivers behave like they do on other Unixy systems: the COPYFILE_DISABLE environment variable. Setting this variable (to any value, even the empty string), will prevent the archivers from generating ._*
archive members to represent any extended information associated with the archived files. Its presence will also prevent the archivers from trying to interpret such archive members as extended information.
COPYFILE_DISABLE=1 tar czf new.tar.gz …
COPYFILE_DISABLE=1 tar xzf unixy.tar.gz …
You might set this variable in your shell’s initialization file if you want to work this way more often than not.
# disable special creation/extraction of ._* files by tar, etc. on Mac OS X
COPYFILE_DISABLE=1; export COPYFILE_DISABLE
Then, when you need to re-enable the feature (to preserve/restore the extended information), you can “unset” the variable for individual commands:
(unset COPYFILE_DISABLE; tar czf new-osx.tar.gz …)
The archivers on Mac OS X 10.4 also do something similar, though they use a different environment variable: COPY_EXTENDED_ATTRIBUTES_DISABLE
You can use this command to backup all your dotfiles (.<something>
) in your $HOME
directory:
$ cd ~
$ find . -maxdepth 1 -type f -name ".*" -exec tar zcvf dotfiles.tar.gz {} +
I researched this quite a bit and came up empty. The limiting factor would be that when tar
is performing it's excludes, the trailing slash (/
) that shows up with directories is not part of the equation when tar is performing its pattern match.
Here's an example:
$ tar -v --create --file=do.tar.gz --auto-compress --no-recursion --exclude={'.','..','.*/'} .*
.qalculate/
.qt/
.qterm/
.qtoctave/
.RapidSVN
.RData
.Rhistory
This variant includes an exclude of .*/
and you can see with the verbose switch turned on to tar, -v
, that these directories are passing through that exclude.
I thought maybe the switches --no-wildcards-match-slash
or --wildcards-match-slash
would relax the greediness of the .*/
but this had no effect either.
Taking the slash out of the exclude, .*
wasn't an option either since that would tell tar
to exclude all the dotfiles and dotdirectories:
$ tar -v --create --file=do.tar.gz --auto-compress --no-recursion --exclude={'.','..','.*'} .*
$
So the only other alternative I can conceive is to provide a list of files to tar
. Something like this:
$ tar -v --create --file=do.tar.gz --auto-compress --no-recursion --wildcards-match-slash --exclude={'.','..','.*/'} $(ls -aF | grep -E "^\..*[^/]$")
.RapidSVN
.RData
.Rhistory
This approach has issues if the number of files exceeds the maximum amount of space for passing arguments to a command would be one glaring issue. The other is that it's ugly and overly complex.
There doesn't appear to be a straight-forward and elegant way to acomplish this using tar
& regular expressions. So as to @terdon's comment, find ... | tar ...
is really the more appropriate way to do this.
Best Answer
The easy way, if you don't particularly need to use
-C
to telltar
to change to some other directory, is to simply specify the full path to the archive on the command line. Then you can be in whatever directory you prefer to create the directory structure that you want inside the archive.The following will create the archive
/var/www/file.tar.gz
and putfile1
from the current directory (whatever that happens to be) in it, with no in-archive path information.The path (to either the archive, the constituent files, or both) can of course also be relative. If
file1
is in/tmp
, you are in/var/spool
and want to create the archive in/var/www
, you could use something like:There's a million variations on the theme, but this should get you started. Add the
v
flag if you want to see whattar
actually does.