I can probably write a shell script to find files only, then pass the list to tar, but I am wondering whether there already is a built-in feature in tar that allows doing just that, in a single command line?
For example, I found the --no-recursion switch, but when I do:
tar --no-recursion -cvf mydir.tar mydir
It only archives the names of the entries in the directory (including subdirectories!), but it doesn’t archive any files.
I also tried:
tar --no-recursion -cvf mydir.tar mydir/*
But while it archives files only, it also archives the names of the subdirectories.
Is there a way to tell tar files only, no directories?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
When you want to use find with tar, the best way is to use cpio instead of tar. cpio can write tar archives and is designed to take the list of files to archive from stdin.
find mydir -maxdepth 1 -type f -print0 | cpio -o -H ustar -0 > mydir.tar
Using find and cpio is a more unix-y approach in that you let find do the file selection with all the power that it has, and let cpio do the archiving. It is worth learning this simple use of cpio, as you find it easy to solve problems you bang your ahead against when trying tar.
Method 2
As camh points out, the previous command had a small problem in that given too many file names, it would execute more than once, with later invocations silently wiping out the previous runs. Since we’re not compressing too, we can append instead of overwrite:
find mydir -maxdepth 1 -type f -print0 | xargs -0 tar Avf mydir.tar
find mydir -maxdepth 1 -type f -exec tar Avf mydir.tar {} +
Iocnarz’s answer of using tar‘s --null and -T options works as well. If you have cpio installed, camh’s answer using it is also fine. And if you have zsh and don’t mind using it for a command, Gilles’s answer using a zsh glob (*(.)) seems the most straightforward.
The key was the -maxdepth option.
Final answer, dealing with spaces appropriately:
find mydir -maxdepth 1 -type f -print0 | xargs -0 tar cvf mydir.tar
This should also work:
find mydir -maxdepth 1 -type f -exec tar cvf mydir.tar {} +
Method 3
I’m not sure I understand your requirements. If you want to store the regular files in mydir but not its subdirectories, the easiest way is to use zsh, where matching regular files only is the simple matter of using the . glob qualifier:
tar cf mydir.tar mydir/*(.)
Method 4
You may even use find ... -print0 and tar ... --null directly without using xargs at all.
find . -maxdepth 1 -type f -print0 | tar cvf mydir.tar --null -T -
In the given example, the --no-recursion option to tar is not necessary because only paths of files (and not directories) will be passed from find to tar.
Using the --no-recursion option to tar in the following example, however, prevents tar from double archiving directories. find will do the directory tree recursion instead of tar then.
# compare find . -print0 | tar cf mydir.tar --null -T - tar -tf mydir.tar | nl find . -print0 | tar cf mydir.tar --null --no-recursion -T - tar -tf mydir.tar | nl
Method 5
As the introductory paragraph in man tar says (last sentence),
The use of a directory name always implies that the
subdirectories below should be included in the archive.
Which I understand as a “no” answer to your question.
Method 6
star -c -C startdir -find . ! -type d > out.tar
Omit -C startdir and replace . with startdir if it should appear in the archive.
This is the most efficient method based on the features of libfind. Libfind also offers primaries -chown -chgrp -chmod that modify struct stat in place and allow to archive different metadata. This also works in list and extract mode and avoids the need to extract the whole archive in many cases.
Method 7
I might have found a solution.
find mydir -type f -printf '%P'|tar czvf mydir.tar.gz -C mydir --null -T -
This might be costly a little, but anyway it will work, because this doesn’t depend on xargs.
Method 8
dir=your_dir ; cd $dir ; tar -cvf file.tar `find . -maxdepth 1 -type f -print`
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0