26

I want to iterate among sub directories of my current location and gzip each file seperately. For zipping files in a directory, I use

for file in *; do gzip "$file"; done

but this can just work on current directory and not the sub directories of the current directory. How can I rewrite the above statements so that It also zips the files in all subdirectories?

user unknown
  • 35,537
  • 11
  • 75
  • 121
Farshid
  • 5,134
  • 9
  • 59
  • 87

4 Answers4

62

I'd prefer gzip -r ./ which does the same thing but is shorter.

Supernormal
  • 962
  • 8
  • 15
59

No need for loops or anything more than find and gzip:

find . -type f ! -name '*.gz' -exec gzip "{}" \;

This finds all regular files in and below the current directory whose names don't end with the .gz extension (that is, all files that are not already compressed). It invokes gzip on each file individually.


Edit, based on comment from user unknown:

The curly braces ({}) are replaced with the filename, which is passed directly, as a single word, to the command following -exec as you can see here:

$ touch foo
$ touch "bar baz"
$ touch xyzzy
$ find . -exec echo {} \;

./foo
./bar baz
./xyzzy
Adam Liss
  • 47,594
  • 12
  • 108
  • 150
  • 2
    Your last sentence is a common misinformation. Find knows where a filename starts and where it ends. Itself, it hasn't any problems with blanks or linebreaks and other funny things. So ` -exec gzip {}` calls gzip with a single filename, and since no intermediate shell is invoked, which could interpret a blank as delimiter, gzip will receive the whole filename. The hint in the manpage of find seems outdated and means: Your shell could try to interpret {} before passing it to find, but no such shell has been seen [for years](http://unix.stackexchange.com/q/8647/4485). – user unknown Apr 29 '12 at 14:37
  • How about: "find . -type f -print0 | xargs -0r gzip" ? One needn't really exclude .gz files because gzip leaves them alone: "gzip: foo.gz already has .gz suffix -- unchanged" – FreeBird Sep 27 '19 at 07:46
  • `find . -type f -print0 | xargs -0r gzip` will also work perfectly well, but it's slightly less efficient because it starts a new shell, processes more files than necessary (viz. the .gz files), and generates output that can be avoided. On the other hand, if you want to see _all_ the files that `find` considers, this is a great way to do that. Like most tasks, there are plenty of ways to accomplish this, each with its benefits and drawbacks. – Adam Liss Sep 28 '19 at 16:39
6
find . -type f | while read file; do gzip "$file"; done
Tim Pote
  • 27,191
  • 6
  • 63
  • 65
  • 1
    what if a file contains spaces or other special chars ? that wont work with `for` there – c00kiemon5ter Apr 28 '12 at 13:35
  • 1
    @c00kiemon5ter Does an answer that works, but may be incomplete deserve a downvote? According to SO "Use your downvotes whenever you encounter an egregiously sloppy, no-effort-expended post, or an answer that is clearly and perhaps dangerously incorrect." This answer is none of those things. Incomplete, somewhat sloppy, but not incorrect. You should probably have let the upvote process take its toll and left a comment. – Tim Pote Apr 28 '12 at 13:40
  • imo, the answer is wrong. Farshid never specified that the files contain no special characters, so your answer only answers a special case of the question. You're better of using `find .. | while read ..`. Correct your answer and I will be the first to upvote. But dont ask me to promote incorrect (imo) answers. – c00kiemon5ter Apr 28 '12 at 13:50
  • Because your answer was more correct, and you've inexplicably taken it down, I've changed my answer to be what yours was. Just note that "not promoting" does not necessarily mean actively downvoting. I would have altered my answer or taken it down after your comment alone. – Tim Pote Apr 28 '12 at 14:03
0

I can't comment on the top post (yet...), but I read in the man pages of "find" that -execDir is safer than -exec because the command is done in the subdirectory where the match is found, rather than the parent directory where "find" is ran from.

If anyone would like to use a regex with to locate specific files in a subdirectory to zip, I'd recommend using

find ./ -type f -name 'addRegexHere' -execdir gzip -k "{}" \;

if you don't need regex's, stick with the recursive gzip call above (or below, if I gain any traction haha)

source

Ben Trono
  • 27
  • 7