[linux] How to tar certain file types in all subdirectories?

I want to tar and all .php and .html files in a directory and its subdirectories. If I use

tar -cf my_archive *

it tars all the files, which I don't want. If I use

tar -cf my_archive *.php *.html

it ignores subdirectories. How can I make it tar recursively but include only two types of files?

This question is related to linux tar

The answer is


If you're using bash version > 4.0, you can exploit shopt -s globstar to make short work of this:

shopt -s globstar; tar -czvf deploy.tar.gz **/Alice*.yml **/Bob*.json

this will add all .yml files that starts with Alice from any sub-directory and add all .json files that starts with Bob from any sub-directory.


This will handle paths with spaces:

find ./ -type f -name "*.php" -o -name "*.html" -exec tar uvf myarchives.tar {} +

One method is:

tar -cf my_archive.tar $( find -name "*.php" -or -name "*.html" )

There are some caveats with this method however:

  1. It will fail if there are any files or directories with spaces in them, and
  2. it will fail if there are so many files that the maximum command line length is full.

A workaround to these could be to output the contents of the find command into a file, and then use the "-T, --files-from FILE" option to tar.


find ./ -type f -name "*.php" -o -name "*.html" -printf '%P\n' |xargs tar -I 'pigz -9' -cf target.tgz

for multicore or just for one core:

find ./ -type f -name "*.php" -o -name "*.html" -printf '%P\n' |xargs tar -czf target.tgz


Put them in a file

find . \( -name "*.php" -o -name "*.html" \) -print > files.txt

Then use the file as input to tar, use -I or -T depending on the version of tar you use

Use h to copy symbolic links

tar cfh my.tar -I files.txt 

tar -cf my_archive `find ./ | grep '.php\|.html'`

Use "find" and "grep" to get all path of .php and .html files in all directory and its sub-directories. Then pass those path information to tar to compress.

Please be careful with those symbol ` and '. Note also that this will hit the limit of how many characters your shell will allow on the command line, unlike some of the other answers.