I need to compress and decompress each of the files of a particular type say *.html in their respective location. For decompression, I used following command, it seemed to work for me:

find dir -name "*.html.tar.gz" -exec tar -xvzf {} \;

I'm able to see *.htmp.tar.gz in their respective directories.

For compression, I'm trying following command but it is not working as concatenation is not happening to the argument from find:

find dir -name "*.html" -exec tar -cvzf {}.tar.gz {} \;

Please suggest solution to this and let me know if solution to the decompression is not foolproof.

EDIT: Although I've right now used gunzip which do not require target name, but I'm wondering if tar is not possible at all. So, waiting for answer which solves the original problem.

EDIT: the requirement is to have a single command because I need to run it through fork() and exec() command from C function. So, I think piping is not possible.

EDIT: Also I'm looking for efficient way, because I want as little overhead as possible to the time taken for compression.

  • 2
    So you want to create an archive for each single file? Are you sure it's not okay for you to compress the html files directly?
    – Philippos
    Mar 9, 2017 at 6:39
  • Here type is just for an example. It could be anything depending upon the user and there might be lot of such files.which needs to be compressed and decompressed. So, finding all such files and compressing them is the only solution. I know I can use loop here, but I want it in single command therefore I used "-exec" option of find command. Mar 9, 2017 at 6:44
  • 2
    Still: Why tar instead of compressing directly? You need to preserve file attributes or what?
    – Philippos
    Mar 9, 2017 at 6:56
  • 1
    @Philippos: Yes I need to preserve file attributes as well. I'm not sure if compressing directly will preserve that or not. Mar 9, 2017 at 7:07
  • 1
    @VivekAgrawal gzip will preserve ownership and file attributes if possible. If running gzip as the user that own the directories and files, or as root, then this is possible.
    – Kusalananda
    Mar 9, 2017 at 7:31

2 Answers 2

find . -name '*.html' -type f -exec sh -c '
   for file do tar czf "$file.tar.gz" "$file"; done' sh {} +

In C:

execlp("find", "find", ".", "-name", "*.html", "-type", "f", "-exec",
       "sh", "-c", "for file do tar czf \"$file.tar.gz\" \"$file\"; done",
       "sh", "{}", "+", 0);

To report failure or any archiving process to the caller, you could improve it to:

find . -name '*.html' -type f -exec sh -c '
  for file do
    tar czf "$file.tar.gz" "$file" || ok=false
  "$ok"' sh {} +

With -exec cmd {} +, find exits with a non-zero exit status if any of the processes it spawns to execute the commands return with a non-zero exit status.

  • Thanks for the answer. Don't you think Invoking shell would take lot of time since it will create whole environment before executing anything? I know I'm putting more conditions to my question but I wanted an efficient way to do it. Mar 11, 2017 at 15:12
  • @Vivek, here with {} +, we're running one sh for every few thousand files (as much as can fit in the maximum number of arguments). The start-up time of that sh will be negligible compared to that of the thousands tar (and possibly thousands gzip if your tar invokes gzip for compressing the archive). Mar 11, 2017 at 18:01

You have to use xargs to achieve this:

find "dir" -name "*.html" -print0 | xargs -0 -n1 -I % tar zcpf %.tar.gz %

It handles almost all special characters in filenames.

  • This is really informative. Thanks for this info. Actually my requirement was to run single command through fork and exec within C function. So piping will not work for me, I think. BTW, I was trying to upvote your answer but unable to do so because of less reputation. :( Mar 9, 2017 at 15:36
  • Can we convert this in a single command? Mar 9, 2017 at 16:04
  • If you want to handle files with space in their name, then no. But you can always put it into a file, save it as "something.sh" and call it from wherever you want. Mar 12, 2017 at 17:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .