Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to backup all the 'dotfiles' (f.e. .zshrc) under my home directory with tar, but excluding the directory structure and all subdirectories.

I've tried it several times with different commands, but the best i achieved was an archive which included the hidden directories under $HOME as well.

#!/bin/zsh
BACKUPFILE=dotfile_backup.tar.gz
tar --create --file=$HOME/$BACKUPFILE --auto-compress --no-recursion --exclude=. --exclude=.. --exclude=*/ --directory=$HOME .*

I also thought about using find and piping the result to tar, but with no luck. Does somebody know how to achieve this - seemingly easy - task?

PS: Most of the time when I'm using tar to create an archive, i have to think about xkcd comic:

xkcd 1168 :)

share|improve this question
    
The answer of sim works, but if someone got a regex that matches only the hidden files, please post it! –  klingt.net Jul 19 '13 at 15:05
1  
Surely this would be better achieved with your shell. I understand that zsh has globs that select only files -- *(.) -- and I think it excludes . and .. from .* by default (and they wouldn't be picked up by .*(.) anyway, since it selects only files). I don't use zsh myself, so I'm not sure enough to turn this into an answer. –  evilsoup Jul 19 '13 at 20:20
add comment

3 Answers

up vote 5 down vote accepted

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 {} +

regex using just tar?

method #1

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.

method #2

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={'.','..','.*'} .*
$

method #3 (Ugly!)

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.

so what did we learn?

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.

share|improve this answer
    
I really wanted to get it done with regex, but i should have known that it won't work that way :) –  klingt.net Jul 19 '13 at 15:04
    
@klingt.net - it should be possible, I'm looking now. –  slm Jul 19 '13 at 15:05
    
@klingt.net why would you prefer the more complicated way? Using regex you will probably need to escape the leading dot and will have trouble ignoring . and ... I am sure it is possible as slm will probably demonstrate but I don't see why it would be worthwhile. –  terdon Jul 19 '13 at 15:08
1  
@klingt.net - everything that the find command finds get's passed as an argument to tar. The {} says where you want those results to go in the corresponding -exec command. The + says to add as many results from find as will fit on the command line and call tar only a couple of times rather than every time a result is found. –  slm Jul 19 '13 at 15:12
1  
@klingt.net - there isn't a way to accomplish this using regex and tar because there is no way to isolate the dot directories (.blah/). Tar doesn't use the trailing slash when doing the exclude. –  slm Jul 19 '13 at 15:59
show 3 more comments

This kind of control over matching files is way outside tar's comfort zone. Its rules for matching files are limited to simple matches over names.

find is one way, but since you have zsh, you have it easier:

tar -cf "$HOME/$BACKUPFILE" --auto-compress .*(.)

That . in parentheses at the end of the wildcard expression is a glob qualifier that says “only match regular files”.

Symbolic links to regular files are not matched. If you change to .*(-.), they will be included, but the file won't end up in the archive unless it's also included. If you want to replace symbolic link by their targets, make that .*(-.:A) — :A adds the history expansion modifier that resolves all symbolic links to a path that doesn't use symbolic links.

share|improve this answer
add comment

This answer is taken from slm's but I also will tell you how to include directories.

To zip up dot files in your home directory:

$ cd
$ find . -maxdepth 1 -type f -name ".?*" -exec tar czfv dotfiles.tgz {} +

If you want to include directories:

$ find . -maxdepth 1 -name ".?*" -exec tar czfv dotfiles.tgz {} +

The ? is optional in the first command, but not in the second, otherwise, find will include the '.' directory.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.