Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I would like to create a tarball that contains files from a directory that have a ctime of less than 30 days. Most tutorials I have found have basically recommended doing something like this:

tar cvf foo.tar $(find ~/POD -type f -ctime -30)

The problem is that a lot of the files that I want to tar up contain spaces in their name. This means that the tar command will delimit based on a spaces, which means that the full file paths will be broken up.

So now I'm trying to make the find command return a list of quoted file paths. So here's what I have tried:

find . -type f -ctime -30  | xargs printf "\"%s\"\n"

But this command also broke up all of the file names based on spaces. So then I tried this:

oldifs=$IFS
IFS=\n
find . -type f -ctime -30  | xargs printf "\"%s\"\n"
IFS=$oldifs

But this gave me the same results.

Is there a way I can pass the full path names to tar and have everything work with spaces in their names?

share|improve this question
add comment

3 Answers

up vote 6 down vote accepted

GNU tar has a -T option to take the list of files from a specified file. I would use find ... -print0 | tar cfzT outfile.tgz - --null so tar receives null-terminated filenames on stdin.

share|improve this answer
    
Worked like a charm. Thanks a ton geekosaur! –  Tom Purl Jun 3 '11 at 19:43
add comment

The null terminated output piped to tarsuggested by geekosaur should do the trick, but you can also do this with the -exec option of find. Find knows that this is a tough problem so they solved it, you just have to turn things around backwards from what you first tried to do with tar … $(find …) and use find to call tar instead like this:

find . -type f -ctime -30 -exec tar cfz outfile.tgz {} +
share|improve this answer
1  
Problem: If the list of files grows too long, tar will run more than once, and outfile.tgz will end up with only the contents of the last run. Go with geekosaur's answer. –  Steven Monday Jun 4 '11 at 0:21
add comment

You almost had it. You need to escape \n like $'\n' to assign a new line to a variable.

oifs=$IFS; IFS=$'\n'; tar cvf foo.tar $(find ~/POD -type f -ctime -30); IFS=$oifs

See the Quoting section of the bash man page for more information.

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.