6

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?

Caleb
  • 11,813
  • 4
  • 36
  • 49
Tom Purl
  • 549
  • 1
  • 3
  • 13

3 Answers3

6

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.

geekosaur
  • 7,175
  • 1
  • 20
  • 19
1

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 {} +
Caleb
  • 11,813
  • 4
  • 36
  • 49
  • 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 04 '11 at 00:21
0

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.

Jeff Strunk
  • 2,127
  • 1
  • 24
  • 29