81

How can I pipe information into tar specifying the names of the file?

CSchulz
  • 10,882
  • 11
  • 60
  • 114
Kristopher Ives
  • 5,838
  • 7
  • 42
  • 67

7 Answers7

118

Something like:

tar cfz foo.tgz --files-from=-

But keep in mind that this won't work for all possible filenames; you should consider the --null option and feed tar from find -print0. (The xargs example won't quite work for large file lists because it will spawn multiple tar commands.)

fuzzyTew
  • 3,511
  • 29
  • 24
geekosaur
  • 59,309
  • 11
  • 123
  • 114
23

As already pointed out by geekosaur, there is no need to pipe the output of find to xargs because it is possible to pipe the output of find directly to tar using find ... -print0 | tar --null ....

Note the slight differences between gnutar and bsdtar in excluding the archive file though.

# exclude file.tar.gz anywhere in the directory tree to be tar'ed and compressed
find . -print0 | gnutar --null --exclude="file.tar.gz" --no-recursion -czf file.tar.gz --files-from -
find . -print0 | bsdtar --null --exclude="file.tar.gz" -n -czf file.tar.gz -T -

# bsdtar excludes ./file.tar.gz in current directory by default
# further file.tar.gz files in subdirectories will get included though
# bsdtar: ./file.tar.gz: Can't add archive to itself
find . -print0 | bsdtar --null -n -czf file.tar.gz -T -

# gnutar does not exclude ./file.tar.gz in current directory by default
find . -print0 | gnutar --null --no-recursion -czf file.tar.gz --files-from -
marco
  • 231
  • 2
  • 2
19

Extending geekosaur answer:

find /directory | tar -cf archive.tar -T -

You can use stdin with the -T option.

Note that if you filter files using some condition (e.g. -name option) in general you need to exclude directories in the pipe, otherwise tar will process all their content, that is not what you want. So, use:

find /directory ! -type d -name "mypattern" | tar -cf archive.tar -T -

If you don't use -type, all the content of directories matching "mypattern" will be added !

CODE-REaD
  • 2,819
  • 3
  • 33
  • 60
John Sinclair
  • 191
  • 1
  • 2
  • I think this method is better that others, because you can pipe anything that outputs to stdout – daks Sep 17 '13 at 07:20
  • 1
    You may want to consider being specific about the file types using `find`. Specifically, I would do `find -type f`. This will disclude symlinks, character devices, etc. If you're interested in empty directories than `find -type f -o -type d`. – JamesThomasMoon Sep 30 '15 at 02:32
  • @JamesThomasMoon1979, is not better option to use `find -path dir/to/exclude -prune`? rather then avoiding dir by `type f`? And also, you say `mypattern`, but is not patter but rather globbin, for pattern is better `find -regex "patter"` – Herdsman Jun 03 '20 at 20:22
  • Rather than `-type f` to avoid directories, I recommend `! -type d`. This has the advantage of **not** excluding other items such as symbolic links, fifos, etc. – CODE-REaD Jul 07 '21 at 20:43
4
find /directory > filename
tar -T filename -cf archive.tar
Felipe Alvarez
  • 3,720
  • 2
  • 33
  • 42
  • 1
    Will this work for all possible filenames (see [geekosaur's answer](https://stackoverflow.com/questions/2597875/how-can-i-build-a-tar-from-stdin/5200173#5200173))? – Peter Mortensen Jun 27 '18 at 12:53
3

Instead of using pipe you could use backticks, e.g.:

tar cvzf archive.tgz `ls -1 *`

Instead of ls -1 * you can put any other command which produces list of needed to archive files

Laimoncijus
  • 8,615
  • 10
  • 58
  • 81
  • 15
    The only thing is that this will not work if the output of the ls command is longer than the shell's maximum allowed command line size. In such an event, you must do it as one of the other answers say; that permits the list to be arbitrarily long. Also, "find [...] -print0" allows you to create a tar file that has members with special characters, where as the ls method doesn't. This method just isn't as safe or universally applicable. – Michael Trausch Oct 16 '12 at 17:33
2

The tar program has been implemented in a variety of ways. For example, on IBM's version of Unix, AIX, tar uses the -L option rather than -T, and requires a file rather than allowing - to indicate stdin:

Usage: tar -{c|r|t|u|x} [ -BdDEFhilmopRUsvwZ ] [ -Number ] [ -f TarFil e ]
       [ -b Blocks ] [ -S [ Feet ] | [ Feet@Density ] | [ Blocksb ] ]
       [ -L InputList ] [-X ExcludeFile] [ -N Blocks ] [ -C Directory ] File ...
Usage: tar {c|r|t|u|x} [ bBdDEfFhilLXmNopRsSUvwZ[0-9] ] ]
       [ Blocks ] [ TarFile ] [ InputList ] [ ExcludeFile ]
       [ [ Feet ] | [ Feet@Density ] | [ Blocksb ] ] [-C Directory ] File ...
Scott Centoni
  • 1,019
  • 11
  • 13
0

You have to use it different on WINDOWS. Do not use the z parameter because it causes the "Can't add archive to itself" error. In addition, if you dont use the ".tar" in the Zip file name (when using z) parameter, tar.exe will create a extensionless file inside the zip file, which is quite useless for most people.

And, i think most people want a single zip file with the files in it, not a zip file with a tar in it. So thats also a reasion not using the z parameter. However i talk about using tar in Windows, im not familar Linux, may it's different there. So in Windows:

To create a ZIP File inside a directory, with specific files in that directory, use:

tar.exe -cf MyZipFilename.zip file1.txt file2.jpg file3.xyz

To create a ZIP File inside a directory, with wildcard for files in that directory, use:

tar.exe -cf MyZipFilename.zip *.txt *.jpg *.xyzff

To let you view the zipped files, add the v parameter in between. Examples:

tar.exe -cvf MyZipFilename.zip file1.txt file2.jpg file3.xyz

or

tar.exe -cvf MyZipFilename.zip *.txt *.jpg *.xyzff

To create a ZIP File inside a directory, with all files in that directory, use: (the trick is that --exclude is at the beginning)

tar.exe --exclude MyZipFilename.zip -cf MyZipFilename.zip *

Finally, i dont know why you want to use it, but if you want using z the command would be:

tar.exe --exclude MyZipFilename.tar.zip -cvzf MyZipFilename.tar.zip *

Just try it out