2 replaced http://unix.stackexchange.com/ with https://unix.stackexchange.com/
source | link

Here, this is a little difficult because you can't invoke tar -c multiple times (it would start over from a new empty archive at each invocation). But see http://unix.stackexchange.com/questions/5641/tar-up-all-pdfs-in-a-directory-retaining-directory-structure/5650#5650Tar up all PDFs in a directory, retaining directory structure

Here, this is a little difficult because you can't invoke tar -c multiple times (it would start over from a new empty archive at each invocation). But see http://unix.stackexchange.com/questions/5641/tar-up-all-pdfs-in-a-directory-retaining-directory-structure/5650#5650

Here, this is a little difficult because you can't invoke tar -c multiple times (it would start over from a new empty archive at each invocation). But see Tar up all PDFs in a directory, retaining directory structure

1
source | link

Why your attempt failed and how to fix it

You can accumulate a list of file names returned by find, but only if there are no newlines in file names, and you need to take precautions.

When you write an unquoted command substitution or variable expansion, like $LISTOFFILES here, the shell performs word splitting and globbing (wildcard expansion) on the result.

Rule: always put double quotes around command substitutions and variable expansions.
Exception: if you understand why you need to leave off the double quotes, and why it's safe to do so.

Here, you need to leave off the double quotes, because word splitting is what splits the string into newline-separated bits. But by default it also splits at other whitespace characters. So you need to make that safe, and turn off globbing as well. You accomplish the former by setting the IFS variable to a single newline and the latter by invoking set -f.

IFS='
'
set -f
tar cvf backup.tar $LISTOFFILES

Note that there are no backslashes involved. Backslashes are used when you input filenames directly, not when they're produced by commands like find.

The usual way to use find

Rather than parse the output of find, you should make it invoke the command you want to run on the files, through the -exec action. This takes care of the case where there are so many files that the maximum command line length is exceeded: the program is invoked as many timed as necessary.

Here, this is a little difficult because you can't invoke tar -c multiple times (it would start over from a new empty archive at each invocation). But see http://unix.stackexchange.com/questions/5641/tar-up-all-pdfs-in-a-directory-retaining-directory-structure/5650#5650

Easier methods

If there aren't too many files, and you're running ksh93 or bash ≥4 or zsh, then use the ** wildcard to recurse into subdirectories. You need to set some shell options first:

set -o globstar                  # on ksh93
shopt -s globstar -s extglob     # on bash 4
setopt ksh_glob                  # on zsh
tar cvf backup.tar ~/**/*.@(PDF|pdf|ODT|odt)

In zsh, with no particular settings, you can write that pattern as ~/**/*.(PDF|pdf|ODT|odt). After setopt extglob, you can write it as ~/**/(#i)*.(pdf|odt).

Or you can use pax:

pax -w -x ustar -s '/\.pdf$/&/' -s '/\.PDF$/&/' -s '/\.odt$/&/' -s '/\.ODT$/&/' -s '/.*//' ~ >backup.tar

If you don't want the path prefix

There are ways with tar and pax, but the simplest approach is to change to the directory you want to archive first.

( IFS='
'; set -f; cd ~ && tar cvf /path/to/backup.tar $(find . …) )
( cd ~ && pax -w … . ) >backup.tar